Blog. Just Blog

Как снять ограничение на размер изображения в DxO ViewPoint

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Темная сторона Силы | Автор: ManHunter
Скриншот программы DxO ViewPoint
Скриншот программы DxO ViewPoint

Для обработки цифровых фотографий я давно пользуюсь очень классной программой DxO ViewPoint 2. О том, что и как она умеет делать, лучше посмотреть на офсайте, статья не об этом. Дело в том, что после очередного обновления (линейка версий 2.5, если быть точным) DxO ViewPoint 2 наотрез отказалась открывать файлы с моего Nikon D800, при этом предыдущие версии с этими же фотографиями работали без каких-либо затруднений. Из краткой отмазки "Image file cannot be loaded" никакой полезной информации извлечь не удалось. Поскольку программа мне все-таки нужна, и желательно самой новой версии, я решил найти причину такого поведения и устранять ее.

Казалось бы, чем это будет отличаться от обычного разбора какой-нибудь защиты? Находим строчку в файле, находим перекрестные ссылки в дизассемблере, определяем условия срабатывания, патчим код. Но проблема в том, строка сообщения "Image file cannot be loaded" нигде не обнаруживается. Ни в исполняемых файлах, ни в файлах данных, ни в ASCII, ни в юникоде, ни фразой целиком, ни по отдельным словам. Хотя файлы не накрыты никакими упаковщиками или навесными протекторами. Пришлось подходить к проблеме с другой стороны.

При всей моей нелюбви к Qt, на котором написана DxO ViewPoint, его заморочки сейчас сыграли мне на руку. Я имею в виду "говорящие" наименования вызываемых функций, например, "warning@CMessageBox", "CMainWindow::doImageRotation", "DXO_dvpv2::licenseManager" и всякое подобное. Дизассемблер любезно предоставляет всю информацию о названиях в автокомментариях, и просто посмотрев на листинг можно с большой вероятностью узнать, что там происходит. Предположив, что в функции открытия изображения должны быть как-то обозначены ключевые слова "open" и "file", а затем проверяя все подозрительные функции в отладчике, я вышел на функцию, обозначенную как "CMainWindow::doOpenFile" (ну кто бы мог подумать! :)) Точка останова в отладчике подтвердила догадку, что при открытии файла выполняется именно этот код. Прохождение функции в пошаговом режиме под отладчиком также привело к появлению искомого сообщения об ошибке открытия файла.
  1. .text:00412CC4                 push    eax
  2. .text:00412CC5                 lea     eax, [ebp+var_C]
  3. .text:00412CC8                 mov     large fs:0, eax
  4. .text:00412CCE                 mov     ebx, ecx
  5. .text:00412CD0                 mov     edi, [ebp+arg_0]
  6. .text:00412CD3                 push    3BEh
  7. .text:00412CD8                 push    offset aCBambooBambo_0
  8. .text:00412CDD                 lea     eax, [ebp+var_58]
  9. .text:00412CE0                 push    offset aCmainwindowDoo
  10. ; "CMainWindow::doOpenFile"
  11. .text:00412CE5                 push    eax
  12. .text:00412CE6                 call    sub_519C90
  13. .text:00412CEB                 add     esp, 10h
  14. .text:00412CEE                 mov     ecx, edi
  15. .text:00412CF0                 mov     [ebp+var_4], 0
  16. .text:00412CF7                 mov     [ebp+var_41], 0
  17. .text:00412CFB                 call    ds:?isEmpty@QString@@QBE_NXZ
  18. ; QString::isEmpty(void)
  19. .text:00412D01                 test    al, al
  20. .text:00412D03                 jnz     loc_413072
  21. .text:00412D09                 push    0
  22. .text:00412D0B                 push    1
  23. .text:00412D0D                 mov     ecx, ebx
  24. .text:00412D0F                 call    sub_44B560
  25. .text:00412D14                 call    sub_4461E0
  26. .text:00412D19                 mov     esi, eax
  27. .text:00412D1B                 test    esi, esi
  28. .text:00412D1D                 jz      loc_412FC4
  29. .text:00412D23                 push    edi
  30. .text:00412D24                 call    sub_417230
  31. .text:00412D29                 add     esp, 4
  32. .text:00412D2C                 test    al, al
  33. .text:00412D2E                 jz      loc_412FC4
  34. .text:00412D34                 mov     eax, [esi]
  35. .text:00412D36                 push    0
  36. .text:00412D38                 push    offset a2fileopencompl
  37. ; "2fileOpenCompleated(bool)"
  38. .text:00412D3D                 mov     ecx, esi
  39. .text:00412D3F                 call    dword ptr [eax+0BCh]
  40. .text:00412D45                 push    eax
  41. .text:00412D46                 lea     ecx, [ebp+var_28]
  42. .text:00412D49                 call    ds:??0COperationCompletionWaiterWithResult
  43. .text:00412D4F                 mov     eax, [esi]
  44. .text:00412D51                 push    edi
  45. .text:00412D52                 mov     ecx, esi
  46. .text:00412D54                 mov     byte ptr [ebp+var_4], 1
  47. .text:00412D58                 call    dword ptr [eax+40h]
  48. .text:00412D5B                 lea     ecx, [ebp+var_28]
  49. .text:00412D5E                 call    ds:?startWaiting
  50. .text:00412D64                 lea     ecx, [ebp+var_28]
  51. .text:00412D67                 call    ds:?isOperationSuccess
  52. .text:00412D6D                 test    al, al
  53. .text:00412D6F                 jz      loc_412F59
  54. .text:00412D75                 call    sub_4461E0
  55. .text:00412D7A                 mov     edx, [eax]
  56. .text:00412D7C                 lea     ecx, [ebp+var_50]
  57. .text:00412D7F                 push    ecx
  58. .text:00412D80                 mov     ecx, eax
  59. .text:00412D82                 call    dword ptr [edx+104h]
  60. .text:00412D88                 push    eax
  61. .text:00412D89                 mov     ecx, ebx
  62. ; Вызвать функцию проверки
  63. .text:00412D8B                 call    sub_415A20
  64. ; Если результат AL=0, то выполнить переход, иначе сообщение об ошибке
  65. .text:00412D90                 test    al, al
  66. .text:00412D92                 jz      loc_412E8E
  67. .text:00412D98                 push    0
  68. .text:00412D9A                 lea     eax, [ebp+var_48]
  69. .text:00412D9D                 push    offset aSorryFileCould
  70. ; "Sorry, file could not be opened"
  71. .text:00412DA2                 push    eax
  72. .text:00412DA3                 call    sub_427660
  73. .text:00412DA8                 add     esp, 0Ch
  74. .text:00412DAB                 mov     ecx, eax
  75. .text:00412DAD                 push    0
  76. .text:00412DAF                 push    ecx
  77. .text:00412DB0                 mov     eax, esp
  78. .text:00412DB2                 push    ecx
  79. .text:00412DB3                 push    offset unk_5E451C
  80. .text:00412DB8                 push    ebx
  81. .text:00412DB9                 mov     byte ptr [ebp+var_4], 2
  82. .text:00412DBD                 mov     dword ptr [eax], 400h
  83. .text:00412DC3                 call    ds:?warning@CMessageBox
  84. .text:00412DC9                 add     esp, 14h
  85. .text:00412DCC                 lea     ecx, [ebp+var_48]
  86. .text:00412DCF                 mov     byte ptr [ebp+var_4], 1
  87. .text:00412DD3                 call    ds:??1QString@@QAE@XZ
В исходнике видно, что по перекрестной ссылке обозначена строка "Sorry, file could not be opened", но при этом под отладчиком на экране отображается "Image file cannot be loaded". Qt такой Qt. Используется ли строчка "Sorry, file could not be opened" в качестве индекса для загрузки строки из какого-то невидимого языкового файла, собирается ли фраза из букв, расшифровывается откуда-то - нам уже это не так интересно. Главное, что найдено условие ее проявления - результат функции проверки по адресу 415A20. Вот она:
  1. .text:00415A20 sub_415A20      proc near
  2. .text:00415A20 arg_0           = dword ptr  8
  3. .text:00415A20                 push    ebp
  4. .text:00415A21                 mov     ebp, esp
  5. .text:00415A23                 mov     ecx, [ebp+arg_0]
  6. .text:00415A26                 push    edi
  7. ; Высота изображения
  8. .text:00415A27                 call    ds:?height@QSize ; QSize::height(void)
  9. .text:00415A2D                 mov     ecx, [ebp+arg_0]
  10. .text:00415A30                 mov     edi, eax
  11. ; Ширина изображения
  12. .text:00415A32                 call    ds:?width@QSize ; QSize::width(void)
  13. ; Перемножить ширину на высоту
  14. .text:00415A38                 imul    edi, eax
  15. .text:00415A3B                 xor     eax, eax
  16. ; Результат больше 24000000 (в десятичной)?
  17. .text:00415A3D                 cmp     edi, 16E3600h
  18. ; AL=1 - изображение превышает допустимый размер, открывать нельзя
  19. ; AL=0 - изображение можно открыть
  20. .text:00415A43                 setnle  al
  21. .text:00415A46                 pop     edi
  22. .text:00415A47                 pop     ebp
  23. .text:00415A48                 retn    4
  24. .text:00415A48 sub_415A20      endp
Названия задействованных функций говорят сами за себя. Здесь определяется высота и ширина изображения, оба значения перемножаются и результат произведения не должен превышать 24.000.000 (или 16E3600h в шестнадцатеричной системе счисления). Изображение с фотоаппарата Nikon D800 в максимальном качестве получается 7360х4912 пикселов, несложно посчитать, что произведение высоты на ширину дает число 36.152.320 (36 мегапикселей), которое превышает допустимое значение и потому не проходит проверку. Из-за этого программа отказывается открывать изображение на редактирование.

Чтобы снять ограничение, достаточно пропатчить команду SETNLE AL по адресу 00415A43, заменив ее на двухбайтовую команду XOR EAX,EAX, а оставшийся байт заменив командой NOP. Теперь любое изображение будет успешно проходить проверку на допустимый размер.

Изображение успешно открывается
Изображение успешно открывается

Я могу предположить, зачем сделано это ограничение, скорее всего, чтобы программа не падала от переполнения памяти на очень больших изображениях. И пусть я не собираюсь открывать в DxO ViewPoint гигапиксельные панорамы, терпеть неудобства с проверками размера тоже не намерен. Сигнатура для поиска приметная, можно легко сделать универсальный патч.

Поделиться ссылкой ВКонтакте Поделиться ссылкой на Facebook Поделиться ссылкой на LiveJournal Поделиться ссылкой в Мой Круг Добавить в Мой мир Добавить на ЛиРу (Liveinternet) Добавить в закладки Memori Добавить в закладки Google
Просмотров: 4561 | Комментариев: 4

Внимание! Статья опубликована больше года назад, информация могла устареть!

Комментарии

Отзывы посетителей сайта о статье
Never (05.12.2014 в 10:58):
Спасибо за очередное открытие, в комплект must have забрал.
ManHunter (05.12.2014 в 10:57):
Для исправления перспективы и дисторсии. Пока что самая лучшая из испробованных.
Исходное: http://rghost.ru/private/59431...de/image.png
После обработки: http://rghost.ru/private/59431...40/image.png
Never (05.12.2014 в 10:50):
Ты великолепен! Впрочем как и всегда.
Прога для правки "широких" фотографий?
AyTkACT (03.12.2014 в 10:41):
Qt такой Qt. © Manhunter
Тут и добавить нечего.

Добавить комментарий

Заполните форму для добавления комментария
Имя*:
Текст комментария (не более 2000 символов)*:

*Все поля обязательны для заполнения.
Комментарии, содержащие рекламу, ненормативную лексику, оскорбления и т.п., а также флуд и сообщения не по теме, будут удаляться. Нарушителям может быть заблокирован доступ к сайту.
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2017
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.05 сек. / MySQL: 2 (0.0038 сек.) / Память: 4.5 Mb
Наверх