Blog. Just Blog

Распаковка данных в формате aPLib на Ассемблере

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Образ мышления: Assembler | Автор: ManHunter
Распаковка данных в формате aPLib на Ассемблере
Распаковка данных в формате aPLib на Ассемблере

Вот мы и добрались до одной из самых популярных библиотек для компрессии данных aPLib. Ее разработал Joergen Ibsen в 1998 году, но исходники по какой-то причине до сих пор не раскрыты, хотя сама библиотека бесплатная. За счет превосходных показателей сжатия и легкой интеграции, aPLib используется в некоторых упаковщиках исполняемых файлов. В 2019 году Emmanuel Marty сделал, казалось бы, невозможное. Ему удалось не только отреверсить алгоритм упаковки aPLib, но и улучшить на 5-7% степень сжатия, полностью сохранив при этом совместимость с оригинальным кодом для распаковки. Таким образом, алгоритм aPLib теперь можно считать открытым.

Утилита appack от Joergen Ibsen перед упакованными данными записывает 24-байтный заголовок, в котором находится "магический" маркер (первые два DWORD), размер исходных данных (5-й DWORD), размер упакованных данных (3-й DWORD) и контрольные суммы для проверки целостности (4-й и 6-й DWORD). Упаковщик apultra от Emmanuel Marty выдает просто упакованные данные, поэтому при его использовании размер первоначальных данных для резервирования памяти надо будет получать самостоятельно.
  1. ;---------------------------------------------------
  2. ; Получение размера распакованных данных
  3. ;---------------------------------------------------
  4. ; На входе:
  5. ;   lpCompressed - указатель на упакованные данные
  6. ; На выходе:
  7. ;   EAX = размер распакованных данных
  8. ;---------------------------------------------------
  9. proc aplib_size lpCompressed:DWORD
  10.         pusha
  11.         mov     esi,[lpCompressed]
  12.         xor     edi,edi
  13.  
  14.         mov     al,080h
  15.         xor     edx,edx
  16. .literal:
  17.         inc     esi
  18.         inc     edi
  19. .next_command_after_literal:
  20.         mov     ebx,03h
  21. .next_command:
  22.         add     al,al
  23.         jnz     @f
  24.         lodsb
  25.         adc     al,al
  26. @@:
  27.         jnc     .literal
  28.         add     al,al
  29.         jnz     @f
  30.         lodsb
  31.         adc     al,al
  32. @@:
  33.         jc      .other
  34.         stdcall .get_gamma2
  35.         sub     ecx,ebx
  36.         jae     .not_repmatch
  37.         stdcall .get_gamma2
  38.         jmp     .got_len
  39.  
  40. .not_repmatch:
  41.         mov     edx,ecx
  42.         shl     edx, 8
  43.         mov     dl,[esi]
  44.         inc     esi
  45.  
  46.         stdcall .get_gamma2
  47.         cmp     edx,07D00h
  48.         jae     .increase_len_by2
  49.         cmp     edx,0500h
  50.         jae     .increase_len_by1
  51.         cmp     edx,0080h
  52.         jae     .got_len
  53. .increase_len_by2:
  54.         inc     ecx
  55. .increase_len_by1:
  56.         inc     ecx
  57. .got_len:
  58.         add     edi,ecx
  59.         xor     ecx,ecx
  60.         mov     bl,02h
  61.         jmp     .next_command
  62. .get_gamma2:
  63.         xor     ecx,ecx
  64.         inc     ecx
  65. .gamma2_loop:
  66.         add     al,al
  67.         jnz     @f
  68.         lodsb
  69.         adc     al,al
  70. @@:
  71.         adc     ecx,ecx
  72.         add     al,al
  73.         jnz     @f
  74.         lodsb
  75.         adc     al,al
  76. @@:
  77.         jc      .gamma2_loop
  78.         retn
  79. .other:
  80.         xor     ecx,ecx
  81.         add     al,al
  82.         jnz     @f
  83.         lodsb
  84.         adc     al,al
  85. @@:
  86.         jc      .short_literal
  87.         movzx   edx,byte[esi]
  88.         inc     esi
  89.         inc     ecx
  90.         shr     dl,1
  91.         je      .done
  92.         adc     ecx,ecx
  93.         jmp     .got_len
  94. .short_literal:
  95.         add     al,al
  96.         jnz     @f
  97.         lodsb
  98.         adc     al,al
  99. @@:
  100.         adc     ecx,ecx
  101.         add     al,al
  102.         jnz     @f
  103.         lodsb
  104.         adc     al,al
  105. @@:
  106.         adc     ecx,ecx
  107.         add     al,al
  108.         jnz     @f
  109.         lodsb
  110.         adc     al,al
  111. @@:
  112.         adc     ecx,ecx
  113.         add     al,al
  114.         jnz     @f
  115.         lodsb
  116.         adc     al,al
  117. @@:
  118.         adc     ecx,ecx
  119. .write_zero:
  120.         inc     edi
  121.         jmp     .next_command_after_literal
  122. .done:
  123.         ; EAX = размер распакованных данных
  124.         mov     [esp+28], edi
  125.         popa
  126.         ret
  127. endp
В качестве единственного параметра передается указатель на упакованные данные, на выходе в регистре EAX количество байт, которое получится после распаковки.

Поскольку apultra дает максимальное сжатие, я буду использовать именно ее. В интернетах выложена только 64-битная версия упаковщика, 32-битный вариант мне пришлось собирать самостоятельно из авторских исходников. Оба варианта есть в прилагаемом архиве. Как и в случае с LZSA, код Emmanuel Marty в оптимизации не нуждается, он идеален. От меня потребовалось только подкорректировать некоторые синтаксические конструкции для адаптации исходника к диалекту FASM.
  1. ;------------------------------------------------------------
  2. ; Распаковка данных в формате aPLib
  3. ; Copyright (C) 2019 Emmanuel Marty
  4. ;------------------------------------------------------------
  5. ; На входе:
  6. ;   lpCompressed - указатель на упакованные данные
  7. ;   lpOut - указатель на буфер для распакованных данных
  8. ; На выходе:
  9. ;   EAX = размер распакованных данных
  10. ;------------------------------------------------------------
  11. proc aplib_unpack lpCompressed:DWORD, lpOut:DWORD
  12.         pusha
  13.         mov     esi,[lpCompressed]
  14.         mov     edi,[lpOut]
  15.  
  16.         mov     al,080h
  17.         xor     edx,edx
  18. .literal:
  19.         movsb
  20. .next_command_after_literal:
  21.         mov     ebx,03h
  22. .next_command:
  23.         add     al,al
  24.         jnz     @f
  25.         lodsb
  26.         adc     al,al
  27. @@:
  28.         jnc     .literal
  29.         add     al,al
  30.         jnz     @f
  31.         lodsb
  32.         adc     al,al
  33. @@:
  34.         jc      .other
  35.         stdcall .get_gamma2
  36.         sub     ecx,ebx
  37.         jae     .not_repmatch
  38.         stdcall .get_gamma2
  39.         jmp     .got_len
  40.  
  41. .not_repmatch:
  42.         mov     edx,ecx
  43.         shl     edx, 8
  44.         mov     dl,[esi]
  45.         inc     esi
  46.  
  47.         stdcall .get_gamma2
  48.         cmp     edx,07D00h
  49.         jae     .increase_len_by2
  50.         cmp     edx,0500h
  51.         jae     .increase_len_by1
  52.         cmp     edx,0080h
  53.         jae     .got_len
  54. .increase_len_by2:
  55.         inc     ecx
  56. .increase_len_by1:
  57.         inc     ecx
  58. .got_len:
  59.         push    esi
  60.         mov     esi,edi
  61.         sub     esi,edx
  62.         rep     movsb
  63.         pop     esi
  64.         mov     bl,02h
  65.         jmp     .next_command
  66. .get_gamma2:
  67.         xor     ecx,ecx
  68.         inc     ecx
  69. .gamma2_loop:
  70.         add     al,al
  71.         jnz     @f
  72.         lodsb
  73.         adc     al,al
  74. @@:
  75.         adc     ecx,ecx
  76.         add     al,al
  77.         jnz     @f
  78.         lodsb
  79.         adc     al,al
  80. @@:
  81.         jc      .gamma2_loop
  82.         retn
  83. .other:
  84.         xor     ecx,ecx
  85.         add     al,al
  86.         jnz     @f
  87.         lodsb
  88.         adc     al,al
  89. @@:
  90.         jc      .short_literal
  91.         movzx   edx,byte[esi]
  92.         inc     esi
  93.         inc     ecx
  94.         shr     dl,1
  95.         je      .done
  96.         adc     ecx,ecx
  97.         jmp     .got_len
  98. .short_literal:
  99.         add     al,al
  100.         jnz     @f
  101.         lodsb
  102.         adc     al,al
  103. @@:
  104.         adc     ecx,ecx
  105.         add     al,al
  106.         jnz     @f
  107.         lodsb
  108.         adc     al,al
  109. @@:
  110.         adc     ecx,ecx
  111.         add     al,al
  112.         jnz     @f
  113.         lodsb
  114.         adc     al,al
  115. @@:
  116.         adc     ecx,ecx
  117.         add     al,al
  118.         jnz     @f
  119.         lodsb
  120.         adc     al,al
  121. @@:
  122.         adc     ecx,ecx
  123.         xchg    eax,ecx
  124.         jz      .write_zero
  125.         mov     ebx,edi
  126.         sub     ebx,eax
  127.         mov     al,[ebx]
  128. .write_zero:
  129.         stosb
  130.         mov     eax,ecx
  131.         jmp     .next_command_after_literal
  132. .done:
  133.         sub     edi,[lpOut]
  134.         mov     [esp+28],edi
  135.         popa
  136.         ret
  137. endp
В качестве параметров передается указатель на упакованные данные и указатель на буфер-приемник. На выходе в регистре EAX возвращается количество байт, которое было извлечено из сжатых данных. Размер принимающего буфера в процессе распаковки никак не проверяется, об этом вы должны позаботиться самостоятельно.

В приложении пример программы с исходным текстом, которая извлекает из памяти иконку, упакованную по алгоритму aPLib, и выводит ее на форму. Там же в архиве утилита для упаковки и распаковки данных от Emmanuel Marty.

Пример программы с исходным текстом (FASM)Пример программы с исходным текстом (FASM)

aPLib.Unpack.Demo.zip (200,728 bytes)


Поделиться ссылкой ВКонтакте
Просмотров: 1128 | Комментариев: 2

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

Комментарии

Отзывы посетителей сайта о статье
ManHunter (19.03.2021 в 07:48):
Ну вот, а тут все сразу и со всеми исходниками.
user (18.03.2021 в 23:21):
Когда-то году в 2000-м реверснул распаковщик aPLib,
распаковывал PECO. Заинтересовался тогда этой библиотекой,
начал было ковырять её, но так и забросил, за отсутствием острой надобности.

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

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

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