Добрый день, уважаемые участники! Занялся я исследованием бут-менеджера OSL2000 v9.21 в чисто "ознакомительных целях", т.к. он мне понравился исчерпывающим функционалом, удобным интерфейсом, малым объёмом и тем, что он не мусорит в разделах. Для этого я инсталлировал OSL2000 и выгрузил WinHEX'ом первые 63 сектора в бинарник. Открыв его с помощью IDA 4.9 и пропустив обычный код с проверками я наткнулся на участок кода, который загружает основной код, декодирует его и передаёт ему управление. Привожу код, снабдив для удобства комментариями (org 600h): Код (Text): seg000:0700 mov si, 4 ; начальный сектор для чтения seg000:0703 mov bx, 1000h ; сегмент, куда будут грузиться данные seg000:0706 mov es, bx seg000:0708 mov bx, 100h ; смещение seg000:070B loc_70B: seg000:070B mov dx, 80h ; подготовка данных для чтения диска 80h=hdd0 seg000:070E mov cx, si ; CL=номер сектора для чтения seg000:0710 call sub_67C ; здесь вызывается int 13h функция 2 - чтение ; сектора с пяти попыток, если не удаётся то ; CF=1 если успешно то результат в ES:BX seg000:0713 jb short locret_75A ; на обработку ошибки и выход seg000:0715 inc si ; следующий сектор seg000:0716 add bx, 200h ; сместились в буфере на 512 байт seg000:071A dec ds:word_7A6 ; тут хранится кол-во секторов (55) seg000:071E jnz short loc_70B ; пока все не прочитаем seg000:0720 xor bx, bx seg000:0722 mov dl, 5Ah ; это маска seg000:0724 mov si, 100h ; задаем смещение seg000:0727 mov di, si ; источник и приёмник равны seg000:0729 mov cx, ds:word_7A8 ; тут хранится число байт кода (27908) seg000:072D cld seg000:072E push ds ; сохраняем ds seg000:072F push es ; es по прежнему равен 1000h seg000:0730 pop ds ; ds=es=1000h seg000:0731 loc_731: seg000:0731 ror dl, 1 ; двигаем маску по-кругу seg000:0733 ror dl, 1 seg000:0735 ror dl, 1 seg000:0737 ror dl, 1 seg000:0739 inc dl ; инкремент seg000:073B lodsb ; поместили в al байт из [es:si] seg000:073C xor al, dl ; наложили маску seg000:073E stosb ; поместили al в [es:di] seg000:073F xor ah, ah ; чтобы мусора небыло seg000:0741 add bx, ax ; считаем контрольную сумму seg000:0743 loop loc_731 seg000:0745 pop ds ; востановливаем ds seg000:0746 cmp bx, ds:word_7A4 ; сравниваем CRC seg000:074A jb short locret_75A ; на обработку ошибки и выход seg000:074C cli seg000:074D mov sp, cs ; непонятно зачем, seg000:074F mov ss, sp ; но переместили стэк seg000:0751 mov sp, 0FFFEh seg000:0754 sti seg000:0755 jmp far ptr 1000h:100h ; уходим на декодированный код Для дальнейших изысков я повторил эту операцию таким образом: Код (Text): xor_mask := $5A; for i := 1 to buf1.size do begin asm ror xor_mask,1 ror xor_mask,1 ror xor_mask,1 ror xor_mask,1 inc xor_mask end; buf2.code[i] := buf1.code[i] xor xor_mask; end; где buf1 и buf2 имеют следующую структуру Код (Text): record e01: array [1..416] of byte; // начальные данные первого сектора e02, e03, e04, sector_count, size, e05, e06, e07: word; e08: array [1..5*16] of byte; // конечные данные первого сектора e09: array [1..3*512] of byte; // ещё 3 сектора code: array [1..(63-4)*512] of byte; // собственно код (начинается с 4-го сектора) end; Но в результате получаю на выходе по смещению 800h инструкцию Код (Text): iret и невразумительную кашу. Подскажите, пожалуйста, где я недосмотрел? С уважением, Сергей Игнатов.
Вероятно, в асме ror мотает dl (байт) по кругу, в переписанном коде - в зависимости от размера переменной xor_mask.
Нет, xor_mask имеет размер байт, и даже если заменить на регистр - результат тот-же Код (Text): asm push dx mov dl,xor_mask ror dl,1 ror dl,1 ror dl,1 ror dl,1 inc dl mov xor_mask,dl pop dx end; В таком "лобовом" варианте результат тот-же
serenya Похоже, один декодирует с первого сектора? Но в оригинале расшифровка начинается с четвёртого, если не ошибаемся. К тому времени, когда самосделанный декодер дойдёт до четвёртого сектора, значение xor_mask будет уже не $5A, а... $8D. По идее в этом случае нужно смотреть на 600h. (Первый сектор – ноль, второй – 200h, третий – 400h,..) А вообще, всё декодирование удобнее сделать с помощью скриптов прямо в иде, ага?