Blog. Just Blog

Функции base64 на Ассемблере

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Образ мышления: Assembler | Автор: ManHunter
Алгоритм Base64 может использоваться в пользовательских почтовых приложениях, в качестве одного из уровней защиты шифрованием, для хранения двоичных данных и для решения многих других задачах. В большинстве языков высокого уровня используются штатные функции, в Ассемблере приходится все реализовывать самостоятельно.

Алгоритм Base64 обратимый, то есть из закодированного текста можно в точности получить исходные данные. Начнем с функции кодирования.
  1. ;---------------------------------------------------------------
  2. ; Функция кодирования Base64
  3. ;---------------------------------------------------------------
  4. ; Параметры:
  5. ; lpFrom - указатель на исходные данные
  6. ; lpTo   - указатель на буфер для приема кодированных данных
  7. ; dSize  - размер исходных данных
  8. ; Функция ничего не возвращает
  9. ;---------------------------------------------------------------
  10. proc    base64_encode lpFrom:dword, lpTo:dword, dSize:dword
  11.         pusha
  12.  
  13.         mov     ebx,.base64
  14.         mov     esi,[lpFrom]
  15.         mov     edi,[lpTo]
  16.         mov     ecx,[dSize]
  17.  
  18.         or      ecx,ecx
  19.         jz      .r3
  20. .encode_loop:
  21.         lodsd
  22.         mov     edx,eax
  23.         bswap   edx
  24.         xor     eax,eax
  25.  
  26.         shld    eax,edx,6
  27.         shl     edx,6
  28.         xlatb
  29.         stosb
  30.  
  31.         xor     eax,eax
  32.         shld    eax,edx,6
  33.         shl     edx,6
  34.         xlatb
  35.         stosb
  36.         dec     ecx
  37.         jz      .r2
  38.  
  39.         xor     eax,eax
  40.         shld    eax,edx,6
  41.         shl     edx,6
  42.         xlatb
  43.         stosb
  44.         dec     ecx
  45.         jz      .r1
  46.  
  47.         xor     eax,eax
  48.         shld    eax,edx,6
  49.         shl     edx,6
  50.         xlatb
  51.         stosb
  52.  
  53.         dec     esi
  54.         dec     ecx
  55.         jnz     .encode_loop
  56.  
  57.         jmp     .r3
  58. .r2:
  59.         mov     al,'='
  60.         stosb
  61. .r1:
  62.         mov     al,'='
  63.         stosb
  64. .r3:
  65.         xor     eax,eax
  66.         stosb
  67.         popa
  68.  
  69.         ret
  70.  
  71. .base64 db 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
  72.         db 'abcdefghijklmnopqrstuvwxyz'
  73.         db '0123456789+/'
  74. endp
Параметры вызова: lpFrom - указатель на кодируемые данные, lpTo - указатель на буфер для приема кодированных данных и dSize - размер кодируемых данных. Все параметры обязательные. Размер буфера-приемника должен быть примерно в 1,3 раза больше исходных данных, это обусловлено особенностями алгоритма кодирования.

Функция декодирования. Для удобства использования я поместил код для определения длины строки и таблицу для декодирования прямо в функцию.
  1. ;---------------------------------------------------------------
  2. ; Функция декодирования Base64
  3. ;---------------------------------------------------------------
  4. ; Параметры:
  5. ; lpFrom - указатель на кодированные данные
  6. ; lpTo   - указатель на буфер для приема декодированных данных
  7. ; dSize  - размер кодированных данных, необязательный параметр
  8. ; На выходе:
  9. ; EAX - длина декодированных данных
  10. ;---------------------------------------------------------------
  11. proc    base64_decode lpFrom:dword, lpTo:dword, dSize:dword
  12.         pusha
  13.         ; Если длина строки не указана, то рассчитать
  14.         mov     ecx,[dSize]
  15.         or      ecx,ecx
  16.         jnz     @f
  17.         ; Штатную функцию API не используем
  18.         mov     edi,[lpFrom]
  19.         xor     ecx,ecx
  20.         dec     ecx
  21.         xor     eax,eax
  22.         repne   scasb
  23.         not     ecx
  24.         dec     ecx
  25.         or      ecx,ecx
  26.         jnz     @f
  27.         ; Если длина нулевая, то вернуть пустую строку
  28.         mov     edi,[lpTo]
  29.         xor     eax,eax
  30.         stosb
  31.         jmp     .loc_ret
  32. @@:
  33.         mov     esi,[lpFrom]
  34.         mov     edi,[lpTo]
  35. @@:
  36.         lodsd
  37.         mov     edx,eax
  38.         bswap   edx
  39.  
  40.         movzx   eax,dl
  41.         mov     al,[.base64+eax]
  42.         shrd    ebx,eax,6
  43.         shr     edx,8
  44.         mov     al,dl
  45.         mov     al,[.base64+eax]
  46.         shrd    ebx,eax,6
  47.         shr     edx,8
  48.         mov     al,dl
  49.         mov     al,[.base64+eax]
  50.         shrd    ebx,eax,6
  51.         shr     edx,8
  52.         mov     al,dl
  53.         mov     al,[.base64+eax]
  54.         shrd    ebx,eax,6
  55.  
  56.         bswap   ebx
  57.         mov     [edi],ebx
  58.  
  59.         inc     edi
  60.         inc     edi
  61.         inc     edi
  62.         sub     ecx,4
  63.         js      @f
  64.         jnz     @b
  65. @@:
  66.         mov     al,0
  67.         stosb
  68.         mov     eax,edi
  69.         sub     eax,[lpTo]
  70.         dec     eax
  71.  
  72.         cmp     byte[esi-1],'='
  73.         jne     @f
  74.         dec     eax
  75. @@:
  76.         cmp     byte[esi-2],'='
  77.         jne     .loc_ret
  78.         dec     eax
  79. .loc_ret:
  80.         mov     [esp+28],eax
  81.         popa
  82.         ret
  83.  
  84. .base64 db 43 dup (0), 0x3E, 0x00, 0x00, 0x00, 0x3F, 0x34
  85.         db 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C
  86.         db 0x3D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  87.         db 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
  88.         db 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
  89.         db 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17
  90.         db 0x18, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  91.         db 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21
  92.         db 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29
  93.         db 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31
  94.         db 0x32, 0x33, 133 dup (0)
  95. endp
Параметры вызова: lpFrom - указатель на декодируемые данные, lpTo - указатель на буфер для приема раскодированных данных и dSize - размер декодируемых данных. Поскольку данные, закодированные по алгоритму Base64 могут содержать только печатные символы, то в функции декодирования можно не указывать их длину, она будет посчитана автоматически. Но для этого кодированные данные обязательно должны быть записаны в формате ASCIIZ. На выходе в регистре EAX возвращается размер декодированных данных.

Пример использования обеих функций:
  1. section '.data' data readable writeable
  2. ...
  3. str1         db 'ManHunter / PCL'             ; Строка для кодирования
  4. str2         db 'SGF2ZSBhIE5pY2UgRGF5IQ==',0  ; Закодированная строка
  5. buffer       rb 100h                          ; Буфер-приемник
  6.  
  7. section '.code' code readable executable
  8.         ...
  9.         ; Закодировать строку. Длина строки обязательно указывается
  10.         stdcall base64_encode,str1,buff,15
  11.         ; Теперь buff содержит кодированную строку 'TWFuSHVudGVyIC8gUENM'
  12.         ...
  13.         ; Раскодировать строку. Длина рассчитается автоматически
  14.         stdcall base64_decode,str2,buff,NULL
  15.         ; buff содержит раскодированную строку 'Have a Nice Day!'
  16.         ...
В системной библиотеке crypt32.dll имеются две штатные функции, которые позволяют кодировать и декодировать строки по алгоритму Base64. Использовать их или нет - это вы решите сами, но знать об этих функциях будет полезно. CryptBinaryToString для кодирования и, соответственно, CryptStringToBinary для декодирования.
  1.         CRYPT_STRING_BASE64 = 0x00000001
  2.  
  3.         ; Максимальный размер буфера-приемника
  4.         mov     [output_len],500h
  5.         ; Закодировать строку
  6.         invoke  CryptBinaryToString,data_source,data_len,\
  7.                 CRYPT_STRING_BASE64,output_buff,output_len
  8.         ...
  9.         ...
  10.         ; Максимальный размер буфера-приемника
  11.         mov     [output_len],500h
  12.         ; Раскодировать строку
  13.         invoke  CryptStringToBinary,data_encoded,0,\
  14.                 CRYPT_STRING_BASE64,output_buff,output_len,NULL,NULL
В приложении примеры программ с исходными текстами, которые используют функции кодирования и декодирования по алгоритму Base64.

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

Base64.Demo.zip (9,842 bytes)


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

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

Комментарии

Отзывы посетителей сайта о статье
ManHunter (27.06.2022 в 15:47):
13 лет уже прошло, давно надо было это все переписать нафиг.
Petya (27.06.2022 в 10:09):
Если это не я напорол при копировании, что возможно, то функция врёт относительно длины при передаче ей строки "roiBlKncON8x/8bEFVjbvElBFk2v2HnstcVelgNR14c=". Возвращает 33, хотя в строке ровно 32 байта закодировано.
Grey (24.06.2013 в 13:43):
Все, допер. Расширение поменял туда и обратно. В любом случае спасибо за статью!
ManHunter (24.06.2013 в 13:23):
А какая для ассемблера разница, что кодировать? WMF для него такие же двоичные данные, как JPEG, как этот текст и вообще как все остальное. На входе набор байтов, на выходе набор байтов.
Grey (24.06.2013 в 13:06):
Изображение твоим енкодером в base64. В интернете в основном он-лайновые кодировщики конвертят наиболее распространенные форматы, я хочу в base64 перевести изображение wmf.
ManHunter (24.06.2013 в 12:55):
Для каких целей кодировать? Куда заталкивать?
Grey (24.06.2013 в 12:53):
Чтобы закодировать изображение его нужно без заголовка заталкивать?
ManHunter (13.06.2011 в 01:48):
Нафига тебе 100 метров в base64 переводить??? Решил фильм по почте отправить?
Vladimir (11.06.2011 в 15:57):
Какова скорость работы алгоритма кодирования? Например, для блока памяти размером 100Мбайт.

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

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

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