Blog. Just Blog

Выполнение скриптов JScript и VBScript из памяти

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

Windows Script Host - стандартный компонент операционной системы Windows - сервер выполнения скриптов на языках VBScript и JScript, а также на других, если их обработчики установлены в системе. Сценарии на WSH способны взаимодействовать с программами, имеющими объектный скриптовый интерфейс путем доступа к их объектам и свойствам. За счет этого сценарии могут выполнять операции с файлами и каталогами, системным реестром, базами данных, производить сложные расчеты, манипуляции со строками и т.п. Было бы большим упущением не задействовать подобную мощь в своих программах.

Материал большой, писанины будет много. Перед тем, как использовать какой-то инструмент, надо удостовериться, что он нам доступен. Поэтому начнем с разбора способа получения списка установленных в системе скриптовых движков. Но перед этим традиционная пачка данных, необходимых для работы с нужными нам COM-объектами.
  1. CLSCTX_INPROC_SERVER  = 0x01
  2. CLSCTX_INPROC_HANDLER = 0x02
  3. CLSCTX_LOCAL_SERVER   = 0x04
  4. CLSCTX_REMOTE_SERVER  = 0x10
  5.  
  6. CLSCTX_SERVER = CLSCTX_INPROC_SERVER + CLSCTX_LOCAL_SERVER\
  7.                 + CLSCTX_REMOTE_SERVER
  8. CLSCTX_ALL    = CLSCTX_INPROC_HANDLER + CLSCTX_SERVER
  9. S_OK          = 0
  10.  
  11. ; GUID {0002E005-0000-0000-C000-000000000046}
  12. CLSID_StdComponentCategoriesMgr \
  13.     dd 00002E005h
  14.     dw 00000h
  15.     dw 00000h
  16.     db 0C0h, 000h, 000h, 000h, 000h, 000h, 000h, 046h
  17.  
  18. ; IEnumGUID Interface
  19. struct IEnumGUID
  20.     ; IUnknown
  21.     QueryInterface dd ?   ; 000h
  22.     AddRef         dd ?   ; 004h
  23.     Release        dd ?   ; 008h
  24.     ; IEnumGUID
  25.     Next           dd ?   ; 00Ch
  26.     Skip           dd ?   ; 010h
  27.     Reset          dd ?   ; 014h
  28.     Clone          dd ?   ; 018h
  29. ends
  30.  
  31. ; GUID {0002E013-0000-0000-C000-000000000046}
  32. IID_ICatInformation \
  33.     dd 00002E013h
  34.     dw 00000h
  35.     dw 00000h
  36.     db 0C0h, 000h, 000h, 000h, 000h, 000h, 000h, 046h
  37.  
  38. ; IID_ICatInformation Interface
  39. struct ICatInformation
  40.     ; IUnknown
  41.     QueryInterface            dd ?   ; 000h
  42.     AddRef                    dd ?   ; 004h
  43.     Release                   dd ?   ; 008h
  44.     ; ICatInformation
  45.     EnumCategories            dd ?   ; 00Ch
  46.     GetCategoryDesc           dd ?   ; 010h
  47.     EnumClassesOfCategories   dd ?   ; 014h
  48.     IsClassOfCategories       dd ?   ; 018h
  49.     EnumImplCategoriesOfClass dd ?   ; 01Ch
  50.     EnumReqCategoriesOfClass  dd ?   ; 020h
  51. ends
  52.  
  53. ; GUID {F0B7A1A2-9847-11CF-8F20-00805F2CD064}
  54. CATID_ActiveScriptParse \
  55.     dd 0F0B7A1A2h
  56.     dw 09847h
  57.     dw 011CFh
  58.     db 08Fh, 020h, 000h, 080h, 05Fh, 02Ch, 0D0h, 064h
Для получения списка скриптовых движков используется интерфейс ICatInformation. После инициализации объекта через его метод EnumClassesOfCategories с указанием типа запрашиваемой информации получаем объект списка скриптовых движков. Осталось по очереди перебрать список и получить CLSID каждого из движков.
  1.         ; Инициализировать COM-объект
  2.         invoke  CoInitialize,NULL
  3.  
  4.         ; Создать объект
  5.         invoke  CoCreateInstance,CLSID_StdComponentCategoriesMgr,\
  6.                 NULL,\
  7.                 CLSCTX_ALL,IID_ICatInformation,pCatInformation
  8.         cmp     eax,S_OK
  9.         jne     wmclose
  10.  
  11.         ; Получить список скриптовых движков
  12.         mov     eax,[pCatInformation]
  13.         mov     eax,[eax]
  14.         stdcall dword [eax+ICatInformation.EnumClassesOfCategories],\
  15.                 [pCatInformation],\
  16.                 1,CATID_ActiveScriptParse,0,0,pEnumClasses
  17.  
  18. loc_loop:
  19.         ; Получить следующий объект списка движков
  20.         mov     eax,[pEnumClasses]
  21.         mov     eax,[eax]
  22.         stdcall dword [eax+IEnumGUID.Next],[pEnumClasses],\
  23.                 1,clsid,0
  24.         cmp     eax,S_OK
  25.         jne     loc_done
  26.  
  27.         ; Получить название движка
  28.         invoke  ProgIDFromCLSID,clsid,ProgramID
  29.         ; Получить строку CLSID
  30.         invoke  StringFromCLSID,clsid,ClsidStr
  31.  
  32.         ; Сформировать строку вида "CLSID\{CLSID}"
  33.         invoke  wsprintf,buff,mask1,[ClsidStr]
  34.         add     esp,12
  35.  
  36.         mov     [len],MAX_PATH
  37.  
  38.         ; Получить описание движка из реестра
  39.         invoke  RegGetValue,HKEY_CLASSES_ROOT,buff,\
  40.                 NULL,RRF_RT_REG_SZ,NULL,desc,len
  41.  
  42.         ; [ProgramID] -> строка идентификатора движка
  43.         ; [ClsidStr] -> строка CLSID движка
  44.         ; desc -> строка описания скриптового движка
  45.  
  46.         ; Освободить память
  47.         invoke  CoTaskMemFree,[ProgramID]
  48.         invoke  CoTaskMemFree,[ClsidStr]
  49.  
  50.         ; Следующий объект
  51.         jmp     loc_loop
  52.  
  53. loc_done:
  54.         ; Прибраться за собой
  55.         mov     eax,[pEnumClasses]
  56.         mov     eax,[eax]
  57.         stdcall dword [eax+IEnumGUID.Release],[pEnumClasses]
  58.  
  59.         mov     eax,[pCatInformation]
  60.         mov     eax,[eax]
  61.         stdcall dword [eax+ICatInformation.Release],[pCatInformation]
  62.  
  63.         ; Удалить объект
  64.         invoke  CoUninitialize
На основании полученного значения CLSID при помощи функции ProgIDFromCLSID запрашиваем человекопонятный идентификатор движка, а затем в ветке реестра с названием типа HKEY_CLASSES_ROOT\CLSID\{CLSID_скриптового_движка} находим его подробное описание. При тестировании обратите внимание, что для некоторых языков в системе могут присутствовать несколько различных движков. У них даже может совпадать идентификатор, отличия будут только в CLSID. Эта информация понадобится нам в дальнейшем.

Итак, мы удостоверились, что нужный нам обработчик скриптов в системе присутствует, значит будем запускать скрипты. Перед кодом следует очередная пачка необходимых для работы данных.
  1. ; GUID {00000000-0000-0000-C000-000000000046}
  2. IID_IUnknown \
  3.     dd 000000000h
  4.     dw 00000h
  5.     dw 00000h
  6.     db 0C0h, 000h, 000h, 000h, 000h, 000h, 000h, 046h
  7.  
  8. ; GUID {BB1A2AE1-A4F9-11CF-8F20-00805F2CD064}
  9. IID_IActiveScript \
  10.     dd 0BB1A2AE1h
  11.     dw 0A4F9h
  12.     dw 011CFh
  13.     db 08Fh, 020h, 000h, 080h, 05Fh, 02Ch, 0D0h, 064h
  14.  
  15. ; IID_IActiveScript Interface
  16. struct IActiveScript
  17.     ; IUnknown
  18.     QueryInterface           dd ?   ; 000h
  19.     AddRef                   dd ?   ; 004h
  20.     Release                  dd ?   ; 008h
  21.     ; IActiveScript
  22.     SetScriptSite            dd ?   ; 00Ch
  23.     GetScriptSite            dd ?   ; 010h
  24.     SetScriptState           dd ?   ; 014h
  25.     GetScriptState           dd ?   ; 018h
  26.     Close                    dd ?   ; 01Ch
  27.     AddNamedItem             dd ?   ; 020h
  28.     AddTypeLib               dd ?   ; 024h
  29.     GetScriptDispatch        dd ?   ; 028h
  30.     GetCurrentScriptThreadID dd ?   ; 02Ch
  31.     GetScriptThreadID        dd ?   ; 030h
  32.     GetScriptThreadState     dd ?   ; 034h
  33.     InterruptScriptThread    dd ?   ; 038h
  34.     Clone                    dd ?   ; 03Ch
  35. ends
  36.  
  37. ; GUID {BB1A2AE2-A4F9-11CF-8F20-00805F2CD064}
  38. IID_IActiveScriptParse \
  39.     dd 0BB1A2AE2h
  40.     dw 0A4F9h
  41.     dw 011CFh
  42.     db 08Fh, 020h, 000h, 080h, 05Fh, 02Ch, 0D0h, 064h
  43.  
  44. ; IActiveScriptParse Interface
  45. struct IActiveScriptParse
  46.     ; IUnknown
  47.     QueryInterface  dd ?   ; 000h
  48.     AddRef          dd ?   ; 004h
  49.     Release         dd ?   ; 008h
  50.     ; IActiveScriptParse
  51.     InitNew         dd ?   ; 00Ch
  52.     AddScriptlet    dd ?   ; 010h
  53.     ParseScriptText dd ?   ; 014h
  54. ends
  55.  
  56. ; GUID {DB01A1E3-A42B-11CF-8F20-00805F2CD064}
  57. IID_IActiveScriptSite \
  58.     dd 0DB01A1E3h
  59.     dw 0A42Bh
  60.     dw 011CFh
  61.     db 08Fh, 020h, 000h, 080h, 05Fh, 02Ch, 0D0h, 064h
  62.  
  63. ; IActiveScriptSite Interface
  64. struct IActiveScriptSite
  65.     ; IUnknown
  66.     QueryInterface      dd ?   ; 000h
  67.     AddRef              dd ?   ; 004h
  68.     Release             dd ?   ; 008h
  69.     ; IActiveScriptSite
  70.     GetLCID             dd ?   ; 00Ch
  71.     GetItemInfo         dd ?   ; 010h
  72.     GetDocVersionString dd ?   ; 014h
  73.     OnScriptTerminate   dd ?   ; 018h
  74.     OnStateChange       dd ?   ; 01Ch
  75.     OnScriptError       dd ?   ; 020h
  76.     OnEnterScript       dd ?   ; 024h
  77.     OnLeaveScript       dd ?   ; 028h
  78.     refcount            dd ?
  79. ends
  80.  
  81. ; IActiveScriptError Interface
  82. struct IActiveScriptError
  83.     ; IUnknown
  84.     QueryInterface    dd ?   ; 000h
  85.     AddRef            dd ?   ; 004h
  86.     Release           dd ?   ; 008h
  87.     ; IActiveScriptError
  88.     GetExceptionInfo  dd ?   ; 00Ch
  89.     GetSourcePosition dd ?   ; 010h
  90.     GetSourceLineText dd ?   ; 014h
  91. ends
  92.  
  93. SCRIPTSTATE_CONNECTED = 2
  94. COINIT_MULTITHREADED  = 0
Перед запуском скрипта требуется выполнить ряд подготовительных действий. Во-первых, надо определить какой скриптовый движок будет его обрабатывать. В боевом приложении это можно сделать, проанализировав расширение запускаемого файла со скриптом или, если формат заранее известен, использовать фиксированное значение. В первом случае по соответствующей ProgID определяем CLSID движка с помощью функции CLSIDFromProgID. Повторюсь, при заранее известных данных CLSID можно прописывать как фиксированное значение. После этого создается интерфейс IActiveScript, через который получаем доступ к интерфейсу IActiveScriptParse. На следующем этапе парсер инициализируется, а движку передается "точка привязки", - указатель на методы интерфейса IActiveScriptSite. Их придется реализовывать самостоятельно, об этом я напишу ниже.
  1.         ; Инициализировать COM-объект
  2.         invoke  CoInitializeEx,NULL,COINIT_MULTITHREADED
  3.  
  4.         ; Получить CLSID из названия движка
  5.         invoke  CLSIDFromProgID,szLang,langID
  6.  
  7.         ; Создать объект
  8.         invoke  CoCreateInstance,langID,\
  9.                 NULL,\
  10.                 CLSCTX_ALL,IID_IActiveScript,ActiveScriptEngine
  11.         cmp     eax,S_OK
  12.         jne     loc_exit
  13.  
  14.         ; Получить интерфейс IActiveScriptParse
  15.         mov     eax,[ActiveScriptEngine]
  16.         mov     eax,[eax]
  17.         stdcall dword [eax+IActiveScript.QueryInterface],[ActiveScriptEngine],\
  18.                 IID_IActiveScriptParse,ActiveScriptParser
  19.  
  20.         ; Инициализировать парсер
  21.         mov     eax,[ActiveScriptParser]
  22.         mov     eax,[eax]
  23.         stdcall dword [eax+IActiveScriptParse.InitNew],[ActiveScriptParser]
  24.  
  25.         ; Настроить собственные обработчики методов
  26.         mov     [ActiveScriptSite.QueryInterface],My_QueryInterface
  27.         mov     [ActiveScriptSite.AddRef],My_AddRef
  28.         mov     [ActiveScriptSite.Release],My_Release
  29.         mov     [ActiveScriptSite.GetLCID],My_GetLCID
  30.         mov     [ActiveScriptSite.GetItemInfo],My_GetItemInfo
  31.         mov     [ActiveScriptSite.GetDocVersionString],My_GetDocVersionString
  32.         mov     [ActiveScriptSite.OnScriptTerminate],My_OnScriptTerminate
  33.         mov     [ActiveScriptSite.OnStateChange],My_OnStateChange
  34.         mov     [ActiveScriptSite.OnScriptError],My_OnScriptError
  35.         mov     [ActiveScriptSite.OnEnterScript],My_OnEnterScript
  36.         mov     [ActiveScriptSite.OnLeaveScript],My_OnLeaveScript
  37.  
  38.         ; Заполнить указатель на структуру
  39.         mov     [pActiveScriptSite],ActiveScriptSite
  40.  
  41.         ; Установить точку привязки скрипта
  42.         mov     eax,[ActiveScriptEngine]
  43.         mov     eax,[eax]
  44.         stdcall dword [eax+IActiveScript.SetScriptSite],[ActiveScriptEngine],\
  45.                 pActiveScriptSite
  46.  
  47.         ; Преобразовать текст скрипта в юникод
  48.         invoke  GetProcessHeap
  49.         mov     [hHeap],eax
  50.         invoke  MultiByteToWideChar,CP_ACP,0,szScript,-1,NULL,0
  51.         mov     ebx,eax
  52.         shl     eax,1
  53.         invoke  HeapAlloc,[hHeap],0,eax
  54.         mov     [pMem],eax
  55.         invoke  MultiByteToWideChar,CP_ACP,0,szScript,-1,[pMem],ebx
  56.  
  57.         ; Передать парсеру текст скрипта
  58.         mov     eax,[ActiveScriptParser]
  59.         mov     eax,[eax]
  60.         stdcall dword [eax+IActiveScriptParse.ParseScriptText],\
  61.                 [ActiveScriptParser],\
  62.                 [pMem],\
  63.                 0,0,0,0,0,0,0,0
  64.  
  65.         ; Выполнить скрипт
  66.         mov     eax,[ActiveScriptEngine]
  67.         mov     eax,[eax]
  68.         stdcall dword [eax+IActiveScript.SetScriptState],\
  69.                 [ActiveScriptEngine],\
  70.                 SCRIPTSTATE_CONNECTED
  71.  
  72.         ; Очистить память
  73.         invoke  HeapFree,[hHeap],0,[pMem]
  74.  
  75.         ; Прибраться за собой
  76.         mov     eax,[ActiveScriptParser]
  77.         mov     eax,[eax]
  78.         stdcall dword [eax+IActiveScriptParse.Release],[ActiveScriptParser]
  79.  
  80.         mov     eax,[ActiveScriptEngine]
  81.         mov     eax,[eax]
  82.         stdcall dword [eax+IActiveScript.Close],[ActiveScriptEngine]
  83.  
  84.         mov     eax,[ActiveScriptEngine]
  85.         mov     eax,[eax]
  86.         stdcall dword [eax+IActiveScript.Release],[ActiveScriptEngine]
  87. loc_exit:
  88.         ; Удалить объект
  89.         invoke  CoUninitialize
Дальше текст скрипта загружается из файла или из другого источника в память, в обязательном порядке преобразуется в юникод, после чего передается парсеру. Если парсер смог без ошибок обработать скрипт, то остается только запустить его через метод SetScriptState интерфейса скриптового движка. Останется только освободить память и выделенные ресурсы.

Теперь что касается методов интерфейса IActiveScriptSite. Как можно понять из названий, большинство из них соответствуют определенному этапу выполнения скрипта: запуск, остановка, изменение состояния, возникновение ошибки и т.п. Вы можете добавить в них собственные обработчики событий, но можно просто возвращать ответ-пустышку. А вот методы интерфейса IUnknown обязательны к реализации.
  1. ;----------------------------------------------------------------------------
  2. ; Обработчик метода QueryInterface
  3. ;----------------------------------------------------------------------------
  4. proc My_QueryInterface pthis:DWORD, iid:DWORD, ppvObject:DWORD
  5.         pusha
  6.  
  7.         mov     eax,[ppvObject]
  8.         cmp     eax,0
  9.         jne     @f
  10.         ; E_FAIL
  11.         mov     eax,0x80004005
  12.         jmp     .loc_ret
  13. @@:
  14.         ; Это интерфейс IActiveScriptSite?
  15.         push    4
  16.         pop     ecx
  17.         mov     esi,[iid]
  18.         mov     edi,IID_IActiveScriptSite
  19.         xor     eax,eax
  20.         repe    cmpsd
  21.         jz      .loc_call
  22.  
  23.         ; Это интерфейс IUnknown?
  24.         push    4
  25.         pop     ecx
  26.         mov     esi,[iid]
  27.         mov     edi,IID_IUnknown
  28.         xor     eax,eax
  29.         repe    cmpsd
  30.         jz      .loc_call
  31.  
  32.         ; E_NOINTERFACE
  33.         mov     eax,0x80004002
  34.         jmp     .loc_ret
  35. .loc_call:
  36.         mov     eax,[pthis]
  37.         ; Установить интерфейс
  38.         mov     ecx,[ppvObject]
  39.         mov     [ecx],eax
  40.         mov     ecx,[eax]
  41.         stdcall dword [ecx+IActiveScriptSite.AddRef],eax
  42. .loc_ok:
  43.         ; S_OK
  44.         xor     eax,eax
  45. .loc_ret:
  46.         mov     [esp+28],eax
  47.         popa
  48.         ret
  49. endp
  50.  
  51. ;----------------------------------------------------------------------------
  52. ; Обработчик метода AddRef
  53. ;----------------------------------------------------------------------------
  54. proc My_AddRef pthis:DWORD
  55.         mov     eax,[pthis]
  56.         inc     [eax+IActiveScriptSite.refcount]
  57.         mov     eax,[eax+IActiveScriptSite.refcount]
  58.         ret
  59. endp
  60.  
  61. ;----------------------------------------------------------------------------
  62. ; Обработчик метода Release
  63. ;----------------------------------------------------------------------------
  64. proc My_Release pthis:DWORD
  65.         push    ecx
  66.         mov     eax,[pthis]
  67.         mov     ecx,[eax+IActiveScriptSite.refcount]
  68.         or      ecx,ecx
  69.         jz      @f
  70.         dec     [eax+IActiveScriptSite.refcount]
  71.         dec     ecx
  72. @@:
  73.         mov     eax,ecx
  74.         pop     ecx
  75.         ret
  76. endp
  77.  
  78. ;----------------------------------------------------------------------------
  79. ; Обработчик метода GetItemInfo
  80. ;----------------------------------------------------------------------------
  81. proc My_GetItemInfo pthis:DWORD, objectName:DWORD,\
  82.         dwReturnMask:DWORD, objPtr:DWORD, ppti:DWORD
  83.         ; S_OK
  84.         xor     eax,eax
  85.         ret
  86. endp
  87.  
  88. ;----------------------------------------------------------------------------
  89. ; Обработчик метода OnScriptError
  90. ;----------------------------------------------------------------------------
  91. proc My_OnScriptError pthis:DWORD, scriptError:DWORD
  92.         ; Получить текст строки с ошибкой
  93.         mov     eax,[scriptError]
  94.         mov     eax,[eax]
  95.         stdcall dword [eax+IActiveScriptError.GetSourceLineText],\
  96.                 [scriptError],\
  97.                 tmp
  98.  
  99.         ; Вывести строку с ошибкой
  100.         invoke  MessageBox,0,[tmp],0,MB_ICONERROR
  101.         ; S_OK
  102.         xor     eax,eax
  103.         ret
  104. endp
  105.  
  106. ;----------------------------------------------------------------------------
  107. ; Обработчик метода GetLCID
  108. ;----------------------------------------------------------------------------
  109. proc My_GetLCID pthis:DWORD, plcid:DWORD
  110.         ; S_OK
  111.         xor     eax,eax
  112.         ret
  113. endp
  114.  
  115. ;----------------------------------------------------------------------------
  116. ; Обработчик метода GetDocVersionString
  117. ;----------------------------------------------------------------------------
  118. proc My_GetDocVersionString pthis:DWORD, version:DWORD
  119.         ; S_OK
  120.         xor     eax,eax
  121.         ret
  122. endp
  123.  
  124. ;----------------------------------------------------------------------------
  125. ; Обработчик метода OnScriptTerminate
  126. ;----------------------------------------------------------------------------
  127. proc My_OnScriptTerminate pthis:DWORD, pvr:DWORD, pei:DWORD
  128.         ; S_OK
  129.         xor     eax,eax
  130.         ret
  131. endp
  132.  
  133. ;----------------------------------------------------------------------------
  134. ; Обработчик метода OnStateChange
  135. ;----------------------------------------------------------------------------
  136. proc My_OnStateChange pthis:DWORD, state:DWORD
  137.         ; S_OK
  138.         xor     eax,eax
  139.         ret
  140. endp
  141.  
  142. ;----------------------------------------------------------------------------
  143. ; Обработчик метода OnEnterScript
  144. ;----------------------------------------------------------------------------
  145. proc My_OnEnterScript pthis:DWORD
  146.         ; S_OK
  147.         xor     eax,eax
  148.         ret
  149. endp
  150.  
  151. ; Обработчик метода OnLeaveScript
  152. ;----------------------------------------------------------------------------
  153. proc My_OnLeaveScript pthis:DWORD
  154.         ; S_OK
  155.         xor     eax,eax
  156.         ret
  157. endp
В качестве примера я добавил собственный обработчик ошибок. При срабатывании он будет запрашивать через метод GetSourceLineText интерфейса IActiveScriptError текст строки, в которой эта ошибка произошла.

В приложении примеры программ с исходными текстами, одна из которых выводит список установленных в системе скриптовых движков, а вторая запускает на выполнение скрипт JScript из памяти.

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

Run.Script.Demo.zip (7,607 bytes)


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

Метки: Assembler, COM

Комментарии

Отзывы посетителей сайта о статье
ManHunter (05.03.2024 в 14:50):
Ничего удивительного, малвара очень активно использует такие приколы со скриптами.
Grey (05.03.2024 в 14:49):
Прикольно, заменил на XML, каспер (или бранмауэр) сразу убивает исполняемый файл.
ManHunter (05.03.2024 в 14:10):
szLang = значение "Program ID" из программы enum_engines.exe для соответствующего языка.
Grey (05.03.2024 в 13:41):
Спасибо, интересно. Прости за тупой вопрос, на сайте MS не смог найти: если  в CLSIDFromProgID захочется скормить не JScript а XML или vbs какие заклинания нужно писать для szLang и langID?

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

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

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