опросы читателей не развлекают, тогда может быть они захотят потрещать мозгами после долгих выходных.
предлагается задачка: программа не корректно работает с образами .iso размером более 2Г
для far имеется плагин, который позволяет смотреть в .iso и извлекать файлы, проблема в том что если извлекается файл из .iso за пределами 2Г, он оказывается состоящим из одних нолей.
не долго думая ищем SetFilePointer (не долго, потому что именно через эту функцию двигается указатель смещения в файле), аналогично тому как искали вызов LoadKeyboardLayout в сообщении не надо при старте переключаться на русскую раскладку,
или можно совсем по-простому через F7-F7:
назовем найденную коротенькую функцию, вызывающую SetFilePointer как seek - клавиша Shift-F12 на первом байте функции (здесь начало определяется элементарно, адрес .10001010)
все расписанные параметры функции SetFilePointer:
понятен и протопип: DWORD seek( long lDistanceToMove /*позиция файла*/, DWORD dwMoveMethod /*стартовая точка*/ )
сразу виден корень проблемы: параметр lpDistanceToMoveHigh в NULL, lDistanceToMove считается знаковым и не может быть более 2Г, а хочется до 4Г
опять через F7-F7 поищем ссылки на функцию, названную seek
нашли раз:
нашли два:
нашли три:
отмотаем наверх несколько экранов чтобы увидеть что лежит в регистре ebx
выше дана вся информация, и даже больше чем надо, и даже в картинках для того чтобы уговорить плагин правильно извлекать файлы за пределами 2Г.
если думать будет лень, очень красивое решение будет опубликовано через неделю, не потому что раньше никто не догадается, потому что такие блоги читаются полтора раза в неделю.
предлагается задачка: программа не корректно работает с образами .iso размером более 2Г
для far имеется плагин, который позволяет смотреть в .iso и извлекать файлы, проблема в том что если извлекается файл из .iso за пределами 2Г, он оказывается состоящим из одних нолей.
не долго думая ищем SetFilePointer (не долго, потому что именно через эту функцию двигается указатель смещения в файле), аналогично тому как искали вызов LoadKeyboardLayout в сообщении не надо при старте переключаться на русскую раскладку,
или можно совсем по-простому через F7-F7:
назовем найденную коротенькую функцию, вызывающую SetFilePointer как seek - клавиша Shift-F12 на первом байте функции (здесь начало определяется элементарно, адрес .10001010)
замечаем повыше много nop, которые наверняка не используются (выравнивание после пустой функции по адресу .10001000), и вместо которых можно будет положить патчик если понадобится.
(в скобках замечу что в файле далее есть еще один вызов SetFilePointer, но он к проблеме 2Г не имеет отношения)
для удобства распишем параметры с помощью клавиши точка-с-запятой - курсор поставить на строку с push и нажать ;
все расписанные параметры функции SetFilePointer:
понятен и протопип: DWORD seek( long lDistanceToMove /*позиция файла*/, DWORD dwMoveMethod /*стартовая точка*/ )
сразу виден корень проблемы: параметр lpDistanceToMoveHigh в NULL, lDistanceToMove считается знаковым и не может быть более 2Г, а хочется до 4Г
опять через F7-F7 поищем ссылки на функцию, названную seek
нашли раз:
нашли два:
нашли три:
отмотаем наверх несколько экранов чтобы увидеть что лежит в регистре ebx
выше дана вся информация, и даже больше чем надо, и даже в картинках для того чтобы уговорить плагин правильно извлекать файлы за пределами 2Г.
если думать будет лень, очень красивое решение будет опубликовано через неделю, не потому что раньше никто не догадается, потому что такие блоги читаются полтора раза в неделю.
Проще всего заменить lpDistanceToMoveHigh с нуля на указатель на ноль. В этом случае SetFilePointer будет рассматривать пару 0:lDistanceToMove, как int64, то есть lDistanceToMove станет уже ULONG. Ближайший ноль, имеющися под боком - это только что впихнутый в стек dwMoveMethod (он нулевой во всех трех обращениях к функции seek).
ОтветитьУдалитьТаким образом, seek преобразуется вот в это:
mov eax, [esp][8]
mov edx, [esp][4]
push eax
mov eax, [ecx][8c]
push esp
nop
push edx
push eax
call SetFilePointer
Чтобы не копировать код туда-сюда после push esp добавлен nop.
Вот как-то так. На живом коде не проверял :)
браво! красивое решение с полным разъяснением, но малость повредничаю - до *очень* красивого не хватает чуть-чуть совсем....
ОтветитьУдалитьУ меня есть вопрос.
ОтветитьУдалитьОткуда в прототипе функции seek появились типы long и DWORD ?
из прототипа DWORD SetFilePointer( HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod )
ОтветитьУдалитьпереданные значения не менялись никак внутри seek
Итак, ответ:
ОтветитьУдалитьрешение становиться очень красивым без лишнего NOP, т.е. команда PUSH ESP будет длиной 2 байта: FF F4
ABel получает приз - бесплатную дополнительную версию уже после окончания срока обновлений
Я понимаю, что "это не наш метод", но Far вроде уже давно Open Source :) http://www.farmanager.com/opensource.php?l=ru
ОтветитьУдалить