Blog. Just Blog

Образ мышления: Assembler

То, что не удается запрограммировать на Ассемблере, приходится паять
Образ мышления: Assembler - RSS-канал Образ мышления: Assembler - Карта сайта

Преобразование символических ссылок в путь к файлу

08.02.2019 | Категория: Образ мышления: Assembler | Автор: ManHunter
"По следам наших публикаций". В одной из недавних статей я использовал код для преобразования символических ссылок на файл в привычный путь. Немного поразмыслив, я решил доработать его до полноценной универсальной функции, которая будет приводить любые "кривые" пути и символические ссылки к человекопонятному виду. Функция разворачивает переменные окружения, исправляет обратные слеши, а также обрабатывает символические ссылки вида "\SystemRoot\explorer.exe", "\Device\HarddiskVolume1\WINDOWS\win.ini", "\??\E:\asm\" и "file:///C:/Windows/explorer.exe". Поддерживаются файлы, каталоги и диски.
  1. ;------------------------------------------------------------
  2. ; Функция нормализации пути к файлу или каталогу
  3. ;------------------------------------------------------------
  4. ; Параметры:
  5. ;   lpPath - указатель на исходный путь
  6. ;   lpNorm - указатель на строку с нормализованным путем
  7. ; На выходе:
  8. ;   EAX = 1 - путь успешно нормализован
  9. ;   EAX = 0 - путь не найден
  10. ;------------------------------------------------------------
  11. proc normalize_path lpPath:DWORD,lpNorm:DWORD
  12.         _OBJ_CASE_INSENSITIVE         = 0x00000040
  13.         _FILE_SYNCHRONOUS_IO_NONALERT = 0x00000020
  14.         _FILE_READ_DATA               = 1
  15.  
  16.         ; Тип запрашиваемой информации
  17.         _ObjectNameInformation = 1
  18.  
  19.         ; Структура для получения результата
  20.         struct _OBJECT_NAME_INFORMATION
  21.                 Length        dw ?
  22.                 MaximumLength dw ?
  23.                 Buffer        dd ?
  24.                 String        rw MAX_PATH-1
  25.         ends
  26.  
  27.         ; Структура для юникодной строки
  28.         struct _UNICODE_STRING
  29.                 Length        dw ?
  30.                 MaximumLength dw ?
  31.                 Buffer        dd ?
  32.         ends
  33.  
  34.         ; Структура для статуса выполнения операции
  35.         struct _IO_STATUS_BLOCK
  36.                 Status      dd ?
  37.                 Pointer     dd ?
  38.                 Information dd ?
  39.         ends
  40.  
  41.         ; Структура для атрибутов объекта
  42.         struct _OBJECT_ATTRIBUTES
  43.                 Length                   dd ?
  44.                 RootDirectory            dd ?
  45.                 ObjectName               dd ?
  46.                 Attributes               dd ?
  47.                 SecurityDescriptor       dd ?
  48.                 SecurityQualityOfService dd ?
  49.         ends
  50.  
  51.         locals
  52.                 hFile            dd ?
  53.                 tmp_name         rw MAX_PATH-1
  54.                 dDisk            dd ?
  55.                 szDisk           rw 4
  56.                 result           dd ?
  57.                 szTmp            rw MAX_PATH-1
  58.                 ObjectName       _UNICODE_STRING
  59.                 ObjectAttributes _OBJECT_ATTRIBUTES
  60.                 IoStatusBlock    _IO_STATUS_BLOCK
  61.                 dwSize           dd ?
  62.                 ObjectNameInfo   _OBJECT_NAME_INFORMATION
  63.         endl
  64.  
  65.         pusha
  66.  
  67.         mov     [result],0
  68.  
  69.         ; Преобразовать File URL в путь
  70.         lea     eax,[dwSize]
  71.         mov     dword [eax],MAX_PATH*2
  72.         lea     ebx,[szTmp]
  73.         invoke  PathCreateFromUrl,[lpPath],ebx,eax,0
  74.         or      eax,eax
  75.         jz      @f
  76.  
  77.         mov     ebx,[lpPath]
  78. @@:
  79.         ; Развернуть переменные окружения
  80.         lea     eax,[tmp_name]
  81.         invoke  ExpandEnvironmentStrings,ebx,eax,MAX_PATH*2
  82.  
  83.         ; Исправить обратные слеши
  84.         lea     ebx,[tmp_name]
  85.         mov     esi,ebx
  86.         mov     edi,ebx
  87. .loc_fix_slashes:
  88.         lodsw
  89.         cmp     ax,'/'
  90.         jne     @f
  91.         mov     ax,'\'
  92. @@:
  93.         stosw
  94.         or      ax,ax
  95.         jnz     .loc_fix_slashes
  96.  
  97.         ; Путь уже нормализован?
  98.         cmp     word [ebx+2],':'
  99.         jne     @f
  100.  
  101.         ; Больше ничего делать не требуется
  102.         invoke  lstrcpy,[lpNorm],ebx
  103.         mov     [result],1
  104.         jmp     .loc_ret
  105. @@:
  106.         lea     eax,[ObjectName]
  107.         invoke  RtlInitUnicodeString,eax,ebx
  108.  
  109.         push    _FILE_SYNCHRONOUS_IO_NONALERT
  110.         push    FILE_SHARE_READ+FILE_SHARE_WRITE+FILE_SHARE_DELETE
  111.         lea     eax,[IoStatusBlock]
  112.         push    eax
  113.         lea     ebx,[ObjectAttributes]
  114.         push    ebx
  115.         mov     [ebx+_OBJECT_ATTRIBUTES.Length],sizeof._OBJECT_ATTRIBUTES
  116.         lea     eax,[ObjectName]
  117.         mov     [ebx+_OBJECT_ATTRIBUTES.ObjectName],eax
  118.         mov     [ebx+_OBJECT_ATTRIBUTES.Attributes],_OBJ_CASE_INSENSITIVE
  119.         push    _FILE_READ_DATA+SYNCHRONIZE
  120.         lea     eax,[hFile]
  121.         push    eax
  122.         invoke  NtOpenFile
  123.         or      eax,eax
  124.         jz      @f
  125.  
  126.         ; Файл открыть не удалось
  127.         lea     ebx,[tmp_name]
  128.         invoke  lstrcpy,[lpNorm],ebx
  129.         jmp     .loc_ret
  130. @@:
  131.         lea     ebx,[dwSize]
  132.         ; Получить размер информации
  133.         invoke  NtQueryObject,[hFile],_ObjectNameInformation,NULL,0,ebx
  134.         ; Получить информацию об объекте
  135.         push    ebx
  136.         push    [dwSize]
  137.         lea     eax,[ObjectNameInfo]
  138.         push    eax
  139.         invoke  NtQueryObject,[hFile],_ObjectNameInformation
  140.         or      eax,eax
  141.         jz      @f
  142.  
  143.         ; Имя объекта получить не удалось
  144.         lea     ebx,[tmp_name]
  145.         invoke  lstrcpy,[lpNorm],ebx
  146.         invoke  NtClose,[hFile]
  147.         jmp     .loc_ret
  148. @@:
  149.         ; Сохранить полученное имя
  150.         lea     eax,[ObjectNameInfo]
  151.         lea     eax,[eax+_OBJECT_NAME_INFORMATION.String]
  152.         lea     ebx,[tmp_name]
  153.         invoke  lstrcpy,ebx,eax
  154.  
  155.         ; Закрыть открытый файл
  156.         invoke  NtClose,[hFile]
  157.  
  158.         ; Перебрать все диски, начиная с A:
  159.         mov     [dDisk],1
  160. .loc_find_drive:
  161.         invoke  GetLogicalDrives
  162. @@:
  163.         test    eax,[dDisk]
  164.         jnz     @f
  165.         shl     [dDisk],1
  166.         jnz     @b
  167.  
  168.         ; Диск определить не удалось
  169.         lea     ebx,[tmp_name]
  170.         invoke  lstrcpy,[lpNorm],ebx
  171.         jmp     .loc_ret
  172. @@:
  173.         lea     eax,[szDisk]
  174.         mov     dword [eax],0x003A0041 ; 'A:' в юникоде
  175.         mov     dword [eax+4],0
  176.         mov     ecx,[dDisk]
  177.         bsr     ecx,ecx
  178.         add     dword [eax],ecx
  179.  
  180.         ; Следующий диск
  181.         shl     [dDisk],1
  182.  
  183.         ; Преобразовать букву диска в строку типа \Device\HarddiskVolume1
  184.         lea     eax,[szDisk]
  185.         lea     ebx,[szTmp]
  186.         invoke  QueryDosDevice,eax,ebx,MAX_PATH*2
  187.         or      eax,eax
  188.         ; Диска нет, пропускаем
  189.         jz      @f
  190.         ; Сравнить начало пути со строкой устройства
  191.         mov     ecx,eax
  192.         lea     esi,[tmp_name]
  193.         mov     edi,ebx
  194.         repe    cmpsw
  195.         or      ecx,ecx
  196.         jnz     @f
  197.  
  198.         ; Только буква диска
  199.         lea     eax,[szDisk]
  200.         invoke  lstrcpy,[lpNorm],eax
  201.         mov     [result],1
  202.         jmp     .loc_ret
  203. @@:
  204.         cmp     ecx,1
  205.         jne     .loc_find_drive
  206.         ; Дополнительная проверка корректности пути
  207.         dec     esi
  208.         dec     esi
  209.         cmp     word [esi],'\'
  210.         jne     .loc_find_drive
  211.  
  212.         ; Диск + оставшийся путь к файлу
  213.         lea     eax,[szDisk]
  214.         invoke  lstrcpy,[lpNorm],eax
  215.         invoke  lstrcat,[lpNorm],esi
  216.         mov     [result],1
  217. .loc_ret:
  218.         popa
  219.  
  220.         mov     eax,[result]
  221.         ret
  222. endp
Параметры вызова: lpPath - указатель на юникодную строку с исходным путем, lpNorm - указатель на строку, куда будет записан нормализованный путь к файлу или каталогу. В регистре EAX возвращается результат выполнения операции: 1 - нормализация прошла успешно, 0 - что-то пошло не так, например, не найден объект, на который указывает символическая ссылка, или файл расположен на сетевом диске. В случае неудачи в lpNorm будет записан исходный путь, но с развернутыми переменными окружения и исправленными слешами, или вовсе без изменений, если никаких преобразований не выполнялось.

Читать статью целиком »
Просмотров: 582 | Комментариев: 1

Как получить имя файла, зная его Handle

29.01.2019 | Категория: Образ мышления: Assembler | Автор: ManHunter
В одной программе у меня появилась необходимость получить имя открытого файла, когда известен его хэндл. Полазив по этим вашим интернетам, я нашел немало решений этой задачи, в основном бездумно скопированных с одного сайта на другой. Пришлось разбираться и систематизировать все самому. Итак, самый простой и приятный способ, чтобы получить имя файла по его хэндлу - использовать функцию GetFinalPathNameByHandle.
  1.         ; Получить имя файла по его хэндлу
  2.         invoke GetFinalPathNameByHandle,[hFile],lpName,MAX_PATH,0
На вход подаем хэндл открытого файла, на выходе получаем полный путь к нему. Красота! Но, к сожалению, этот способ работает только на Windows Vista и более новых системах. Если вашему приложению требуется поддержка Windows XP, то придется проверять наличие этой функции в экспорте библиотеки kernel32. Для старых систем есть другой способ. Открытый файл проецируется в память с помощью функций CreateFileMapping и MapViewOfFile, затем с помощью функции GetMappedFileName можно узнать полный путь к спроецированному файлу:
  1.         ; Создать проекцию файла
  2.         invoke  CreateFileMapping,[hFile],NULL,PAGE_READONLY,0,1,NULL
  3.         mov     [hFileMap],eax
  4.         invoke  MapViewOfFile,[hFileMap],FILE_MAP_READ,0,0,1
  5.         mov     [pMem],eax
  6.  
  7.         ; Получить имя спроецированного файла
  8.         invoke  GetCurrentProcess
  9.         invoke  GetMappedFileName,eax,[pMem],lpName,MAX_PATH
  10.  
  11.         ; Прибраться за собой
  12.         invoke  UnmapViewOfFile,[pMem]
  13.         invoke  CloseHandle,[hFileMap]
Имя носителя в строке пути записывается в виде "\Device\HarddiskVolume1", для приведения его к более привычному виду надо пройтись по всем доступным буквам дисков, установленных в системе, каждую преобразовать в имя устройства и сравнить с именем устройства в пути к файлу. Для облегчения операции преобразования символических ссылок я нарисовал отдельную функцию. Способ с проецированием файла неплохой, но у него есть один существенный недостаток: проецирование не работает с файлами нулевой длины. Например, вы не сможете получить имя вновь созданного пустого файла, тогда как функция GetFinalPathNameByHandle прекрасно справляется с этой задачей.

Читать статью целиком »
Просмотров: 688 | Комментариев: 3

Кодирование и декодирование чисел по алгоритму Base58

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

Согласно спецификации, в алфавит Base58 не входят буквенно-цифровые символы, которые имеют сходное написание и могут неоднозначно восприниматься человеком (например, буква "О" и цифра "0"), а также символы, используемые при формировании URL. Вместе с тем, порядок следования символов в алфавите ничем не регламентирован, зависит только от сферы применения кодирования и может быть любым. Для этой статьи я выбрал следующий алфавит Base58:
  1. alpha db '123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ'
  2. alpha_len=$-alpha
Использования своего собственного порядка символов также позволяет добавить немного секурности вашему проекту, затрудняя перебор последовательных идентификаторов. Но вы должны понимать, что целиком надеяться на это ни в коем случае не стоит.

Читать статью целиком »
Просмотров: 706 | Комментариев: 4

Алгоритмы шифрования TEA и XTEA на Ассемблере

13.12.2018 | Категория: Образ мышления: Assembler | Автор: ManHunter

Алгоритмы шифрования TEA и XTEA на Ассемблере

Tiny Encryption Algorithm (TEA) - один из видов блочных алгоритмов шифрования данных. Главными отличиями TEA являются высокая скорость работы, нетребовательность к памяти и простота реализации на различных языках программирования. Не обошлось и без недостатков в виде уязвимости к некоторым типам криптографических атак, но даже несмотря на это алгоритм завоевал широкую популярность в различных системах.

Читать статью целиком »
Просмотров: 1013 | Комментариев: 8

Как изменить цвет кнопок диалогового окна

17.11.2018 | Категория: Образ мышления: Assembler | Автор: ManHunter
Когда-то давно в одной из статей я рассказывал, как менять цвета различных элементов диалоговых окон Windows. Наверняка вы обратили внимание, что элемент типа BUTTON, то есть кнопка, выбивается из общей схемы и на изменение цвета не реагирует должным образом. Решить эту проблему все-таки можно, но для этого придется самостоятельно отрисовывать все компоненты кнопки - фон, рамку и надпись. Зато такой способ открывает неограниченные возможности по кастомизации кнопок.

Первым делом в ресурсах или в функции создания кнопки через CreateWindow(Ex) надо дополнить стиль модифицируемой кнопки параметром BS_OWNERDRAW. С этого момента все функции по рисованию перекладываются на наше приложение. Для этого приложение должно обрабатывать сообщение WM_DRAWITEM. Окну-владельцу кнопки в параметре lParam этого сообщения передается указатель на структуру DRAWITEMSTRUCT, на основании которой мы и будем заниматься рисованием.
  1.         cmp     [msg],WM_DRAWITEM
  2.         je      color_button
  3.         ...
  4.         ...
  5. color_button:
  6.         ; Указатель на структуру DRAWITEMSTRUCT
  7.         mov     ebx,[lparam]
  8.  
  9.         ; Установить режим смешивания фоновых цветов
  10.         invoke  SetBkMode,[ebx+DRAWITEMSTRUCT.hDC],TRANSPARENT
  11.  
  12.         ; Кнопка активна?
  13.         test    [ebx+DRAWITEMSTRUCT.itemState],ODS_SELECTED
  14.         jz      @f
  15.  
  16.         invoke  GetSysColor,COLOR_ACTIVEBORDER
  17.         invoke  CreatePen,PS_SOLID,1,eax
  18.         invoke  SelectObject,[ebx+DRAWITEMSTRUCT.hDC],eax
  19.  
  20.         invoke  GetSysColor,COLOR_3DLIGHT
  21.         invoke  CreateSolidBrush,eax
  22.         invoke  SelectObject,[ebx+DRAWITEMSTRUCT.hDC],eax
  23.  
  24.         ; Прямоугольник с заливкой
  25.         invoke  Rectangle,[ebx+DRAWITEMSTRUCT.hDC],\
  26.                 [ebx+DRAWITEMSTRUCT.rcItem.left],\
  27.                 [ebx+DRAWITEMSTRUCT.rcItem.top],\
  28.                 [ebx+DRAWITEMSTRUCT.rcItem.right],\
  29.                 [ebx+DRAWITEMSTRUCT.rcItem.bottom]
  30.  
  31.         jmp     loc_text
  32. @@:
  33.         ; Установить цвет и стиль рамки
  34.         invoke  GetSysColor,COLOR_3DDKSHADOW
  35.         invoke  CreatePen,PS_SOLID,3,eax
  36.         invoke  SelectObject,[ebx+DRAWITEMSTRUCT.hDC],eax
  37.  
  38.         ; Установить цвет фона
  39.         invoke  GetSysColor,COLOR_HIGHLIGHT
  40.         invoke  CreateSolidBrush,eax
  41.         invoke  SelectObject,[ebx+DRAWITEMSTRUCT.hDC],eax
  42.  
  43.         ; Прямоугольник с заливкой
  44.         invoke  Rectangle,[ebx+DRAWITEMSTRUCT.hDC],\
  45.                 [ebx+DRAWITEMSTRUCT.rcItem.left],\
  46.                 [ebx+DRAWITEMSTRUCT.rcItem.top],\
  47.                 [ebx+DRAWITEMSTRUCT.rcItem.right],\
  48.                 [ebx+DRAWITEMSTRUCT.rcItem.bottom]
  49.  
  50. loc_text:
  51.         ; Длина надписи на кнопке
  52.         invoke  GetWindowTextLength,[ebx+DRAWITEMSTRUCT.hwndItem]
  53.         inc     eax
  54.         mov     [len],eax
  55.         invoke  GetWindowText,[ebx+DRAWITEMSTRUCT.hwndItem],buff,[len]
  56.  
  57.         ; Установить цвет текста
  58.         invoke  SetTextColor,[ebx+DRAWITEMSTRUCT.hDC],0x0000FFFF
  59.  
  60.         ; Для нажатой кнопки сдвинуть текст вниз-вправо
  61.         test    [ebx+DRAWITEMSTRUCT.itemState],ODS_SELECTED
  62.         jz      @f
  63.  
  64.         ; Установить цвет текста
  65.         invoke  SetTextColor,[ebx+DRAWITEMSTRUCT.hDC],0x000000FF
  66.  
  67.         add     [ebx+DRAWITEMSTRUCT.rcItem.left],2
  68.         add     [ebx+DRAWITEMSTRUCT.rcItem.top],2
  69. @@:
  70.         ; Надпись на кнопке
  71.         lea     esi,[ebx+DRAWITEMSTRUCT.rcItem]
  72.         invoke  DrawText,[ebx+DRAWITEMSTRUCT.hDC],buff,[len],esi,\
  73.                 DT_SINGLELINE+DT_VCENTER+DT_CENTER
В зависимости от состояния кнопки, нажата она или нет, меняется цвет фона, цвет текста и стиль рамки. Здесь рамка нарисована единым цветом и толщиной, но при необходимости можно заморочиться и нарисовать "трехмерные" границы с помощью функций MoveToEx и LineTo. Еще было бы правильным проверять, что цвета меняются именно для нужной кнопки, делается это проверкой элемента itemID в структуре DRAWITEMSTRUCT. В приведенном примере я это осознанно пропустил, чтобы не загромождать код.

Читать статью целиком »
Просмотров: 615 | Комментариев: 0

Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2019
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.07 сек. / MySQL: 2 (0.0018 сек.) / Память: 4.75 Mb
Наверх