Захват разрушением указателей.

Тема в разделе "WASM.ZEN", создана пользователем Clerk, 22 авг 2009.

  1. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Множество вопросов при захвате кода, в личку часто пишут про это, но лишь не многие используют обработку исключений. Это определяется самим подходом к захвату. Опишу только общий принцип. Жёсткая модификация кода далее не рассматривается изза своей не актуальности и простоты.
    Одним из основных альтернативных(продвинутых) способов контроля исполнения кода является совокупность из трёх базовых техник:
    o Обработка(отлов) исключения.
    o Трассировка.
    o Бактрейс(развёртка/парсинг цепочки стековых вреймов).

    Принцип заключается в следующем.
    Допусти в какомто месте кода используется обращение к адресу, ссылка на который определена в глобальной(фиксированной) переменной. Для отлова этого обращения значение этой переменной(указатель который она содержит) делается не валидным, указывающем на не валидный адрес. Далее при обращении к этой переменной возникнет исключение. Обработчик исключения имеет контекст потока в котором это исключение возникло. Этот момент является основой для дальнейшей обработки кода до необходимого(целевого) места. Отсюда начинается трассировка кода.
    Целевой код может находится на значительном удалении от текущего, поэтому полная трассировка не применима. Используется трассировка до процедурного ветвления, которое загружает в стек адрес возврата. Этот адрес делается не валидным и на этом трассировка завершается. При возврате из процедуры возникнет исключение, контекст должен быть восстановлен(в частности Eip). Если целевой код находится выше по цепочке стековых фреймов, то выполняется развёртка(бактрейс) их и замена указателей на не валидные. Это позволит получать управление при возврате из процедур.
    Условием необходимым для реализации этой техники является наличие фиксированной глобальной переменной содержащей указатель и отсутствие проверки указателя(например обращение к базе данных загрузчика, ссылка на которую находится в PEB отслеживается, но в User32.dll есть проверки и это место требует специальной обработки). Это могут быть внутренние структуры, указатели на структуры, строки и тп. Также для генерации исключения может быть использована подмена смещений, индексов и тп., которые используются при адресации. Конечной целью такой манипуляции является разрушение указателя, что приведёт к генерации исключения.
    В юзермоде как пример: указатели в TEB, PEB, списки модулей и пр., указатели в секции данных модулей на внутренние структуры, строки и тп. Частным случаем является перемещение структуры. Структура перемещается в конец страницы, следующая страница не выделена и при обращении к полям следующим за последним будет возникать исключение. Часто эта техника является единственно возможной при захвате кода. Для шадова(GUI) может успешно использоваться, так как там активно используются глобальные указатели.

    При выборе сопсоба захвата следует использовать следующее:
    1. Поиск непосредственно указателя на обработчик в структуре или секции данных. Это могут быть калбэки, как частный случай нотификаторы. Сюда можно отнести подмену ссылки на список(структуру). Может использоваться совокупность теневых калбэков с бактрейсом.
    2. Поиск калбэка выше либо ниже по последовательности вызовов процедур. Если такой калбэк существует, то он будет использовать бактрейс(развёртку цепочки стековых фреймов) с подменой адреса возврата в одном из фреймов на свой обработчик.
    3. Если имеется возможность обработки исключения, то ищется способ генерации исключения как можно ближе к целевому коду. Основным способом является разрушение указателей.
    В ядре на высоких IRQL возможности не большие, обычно выполняется замена шлюза в IDT, на низких IRQL обработка исключений в KiDebugRoutine. В юзермоде удалённо исключение обрабатывается посредством подключения отладчика к целевому процессу и обработки отладочных сообщений. Если отладчик не может быть применён, возможна регистрация векторного обработчика исключений. Здесь есть один подводный камень - указатель на VEH в системном списке зашифрован, ключём являются куки, значение уникальное для процесса и оно не может быть получено в юзермоде удалённо. Следует выполнить код в контексте целевого процесса, который установит обработчик.
    4. Жёсткая модификация кода. Атомарный сплайсинг/хотпатч.

    Пример реализации. Допустим имеется код:
    Код (Text):
    1. MainRoutine:
    2.     [...]
    3.     Call SubRoutine1
    4.     [...]
    5.     Call SubRoutine2
    6.     [...]
    7.     [Целевой код]
    8.    
    9. SubRoutine1:
    10.     [...]
    11.     MessageBox(GlobalNameRef, ..)   ; Указатель на строку.
    12.     [...]
    13.     ret
    14.  
    15. SubRoutine2:
    16.     [...]
    17.     ret
    Разрушаем указатель в GlobalNameRef, предварительно сохранив его для последующего восстановления. При обращении к указателю исключение возникнет гдето внутри MessageBox(). Обработчик исключений выполнит бактрейс, найдёт необходимый стековый фрейм с адресом возврата в MainRoutine(), сохранит этот указатель и сделает его не валидным. После чего восстановит в контексте указатель [GlobalNameRef], либо указатель в GlobalNameRef(в этом случае выполняется трассировка инструкции, после её исполнения указатель снова затирается) и выполнит рестарт инструкции. Тред отработает и при возврате из SubRoutine() будет сгенерировано исключение. Так как целевой код находится на некотором удалении от процедурного ветвления на SubRoutine1(), и между ними есть есчо ветвление, а его нужно пропустить, то контекст восстанавливается и выполняется трассировка до входа в SubRoutine2(). После этого как и в предыдущем случае делается не валидным адрес возврата в стеке и тред отпускается. После отработки SubRoutine2() при возврате из неё возникает исключение. Контекст восстанавливается и отсюда начинается трассировка до целевого кода.

    Эта техника эффективна для ядра. Разумеется не всюду это может применяться, но это должно быть основным способом захвата, если не возможна установка калбэков.
     
    shanya0xff нравится это.
  2. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    На вскидку кодес. Поиск LdrpInitializeTls().
    Допустим гдето внутри процедуры имеется ссылка на строку. Соответственно для этой ссылки определён фиксап.
    o Ищем строку в памяти.
    o Ищем фиксап для ссылки на строку.
    o В графе ищем процедуру с инструкцией загружающей ссылку на строку, исходя из адреса найденого анализом фиксапов.
    Код (Text):
    1. ; \IDP\Public\User\Bin\Graph\Dasm\Relocs\Fix.asm
    2. ;
    3.     .686
    4.     .model flat, stdcall
    5.     option casemap :none
    6.  
    7.     include \masm32\include\ntdll.inc
    8.  
    9. GET_CURRENT_GRAPH_ENTRY macro
    10.     Call _$_GetCallbackReference
    11. endm
    12.  
    13. .code
    14. _$_GetCallbackReference::
    15.     pop eax
    16.     ret
    17.  
    18. SEH_Prolog proc C
    19.     pop ecx
    20.     push ebp
    21.     push eax
    22.     Call SEH_GetRef
    23.     push eax
    24.     assume fs:nothing
    25.     push dword ptr fs:[TEB.Tib.ExceptionList]
    26.     mov dword ptr fs:[TEB.Tib.ExceptionList],esp
    27.     jmp ecx
    28. SEH_Prolog endp
    29.  
    30. SEH_Epilog proc C
    31.     pop ecx
    32.     pop dword ptr fs:[TEB.Tib.ExceptionList]
    33.     lea esp,[esp + 3*4]
    34.     jmp ecx
    35. SEH_Epilog endp
    36.  
    37. SEH_GetRef proc C
    38.     GET_CURRENT_GRAPH_ENTRY
    39.     mov eax,dword ptr [esp + 4]
    40.     mov esp,dword ptr [esp + 2*4]   ; (esp) -> ExceptionList
    41.     mov eax,EXCEPTION_RECORD.ExceptionCode[eax]
    42.     mov ebp,dword ptr [esp + 3*4]
    43.     jmp dword ptr [esp + 2*4]
    44. SEH_GetRef endp
    45.  
    46. LdrImageNtHeader proc ImageBase:PVOID, ImageHeader:PIMAGE_NT_HEADERS
    47.     mov edx,ImageBase
    48.     mov eax,STATUS_INVALID_IMAGE_FORMAT
    49.     assume edx:PIMAGE_DOS_HEADER
    50.     cmp [edx].e_magic,'ZM'
    51.     jne @f
    52.     add edx,[edx].e_lfanew
    53.     assume edx:PIMAGE_NT_HEADERS
    54.     cmp [edx].Signature,'EP'
    55.     jne @f
    56.     cmp [edx].FileHeader.SizeOfOptionalHeader,sizeof(IMAGE_OPTIONAL_HEADER32)
    57.     jne @f
    58.     cmp [edx].FileHeader.Machine,IMAGE_FILE_MACHINE_I386   
    59.     jne @f
    60.     test [edx].FileHeader.Characteristics,IMAGE_FILE_32BIT_MACHINE
    61.     je @f
    62.     mov ecx,ImageHeader
    63.     xor eax,eax
    64.     mov dword ptr [ecx],edx
    65. @@:
    66.     ret
    67. LdrImageNtHeader endp
    68.  
    69. ; +
    70. ; Перечисление фиксапов для ссылки.
    71. ;
    72. LdrEnumerateFixups proc uses ebx esi edi ImageBase:PVOID, Ip:PVOID, CallbackRoutine:PVOID, CallbackParameter:PVOID
    73. Local ExitFlag:BOOLEAN
    74.     Call SEH_Epilog_Reference
    75.     Call SEH_Prolog
    76.     invoke LdrImageNtHeader, ImageBase, addr ExitFlag
    77.     test eax,eax
    78.     mov ecx,ExitFlag
    79.     jnz Exit
    80.     mov esi,IMAGE_NT_HEADERS.OptionalHeader.DataDirectory.VirtualAddress[ecx + IMAGE_DIRECTORY_ENTRY_BASERELOC*sizeof(IMAGE_DATA_DIRECTORY)]
    81.     mov edi,IMAGE_NT_HEADERS.OptionalHeader.DataDirectory._Size[ecx + IMAGE_DIRECTORY_ENTRY_BASERELOC*sizeof(IMAGE_DATA_DIRECTORY)]
    82.     test esi,esi
    83.     mov edx,Ip
    84.     mov ecx,IMAGE_NT_HEADERS.OptionalHeader.SizeOfImage[ecx]
    85.     jz Error
    86.     sub edx,ImageBase
    87.     jbe Error
    88.     cmp edx,ecx
    89.     jnb Error
    90.     test edi,edi
    91.     jz Error
    92.     add esi,ImageBase
    93.     add edi,esi ; Limit
    94.     assume esi:PIMAGE_BASE_RELOCATION
    95. Scan:
    96.     mov ebx,[esi].SizeOfBlock
    97.     sub ebx,sizeof(IMAGE_BASE_RELOCATION)
    98.     jbe Error       ; ..
    99.     shr ebx,1
    100. @@:
    101.     movzx eax,word ptr [esi + ebx*2 + sizeof(IMAGE_BASE_RELOCATION) - 2]
    102. ;   push eax
    103. ;   and eax,NOT(0FFFH)
    104. ;   cmp eax,IMAGE_REL_BASED_HIGHLOW
    105. ;   pop eax
    106. ;   jne Error
    107.     and eax,0FFFH
    108.     add eax,[esi].VirtualAddress
    109.     mov ecx,Ip
    110.     add eax,ImageBase
    111.     .if dword ptr [eax] == ecx
    112.     lea edx,ExitFlag
    113.     mov ExitFlag,FALSE
    114.     push edx
    115.     push CallbackParameter
    116.     push eax
    117.     push ImageBase
    118.     Call CallbackRoutine
    119.     cmp ExitFlag,FALSE
    120.     jne Exit
    121.     .endif
    122.     dec ebx
    123.     jnz @b
    124. Next:
    125.     add esi,[esi].SizeOfBlock
    126.     cmp esi,edi
    127.     jb Scan
    128.     xor eax,eax
    129.     jmp Exit
    130. SEH_Epilog_Reference:
    131.     GET_CURRENT_GRAPH_ENTRY
    132. Exit:
    133.     Call SEH_Epilog
    134.     ret
    135. Error:
    136.     mov eax,STATUS_UNSUCCESSFUL
    137.     jmp Exit
    138. LdrEnumerateFixups endp
    139.  
    140. CALLBACK_DATA struct
    141. Routine     PVOID ?
    142. Parameter   PVOID ?
    143. CALLBACK_DATA ends
    144. PCALLBACK_DATA typedef ptr CALLBACK_DATA
    145.  
    146. _$_SearchCallback:
    147.     GET_CURRENT_GRAPH_ENTRY
    148. SearchCallbackInternal proc ImageBase:PVOID, Fixup:PVOID, CallbackData:PCALLBACK_DATA, ExitFlags:PBOOLEAN
    149.     mov eax,Fixup
    150.     mov ecx,CallbackData
    151.     dec eax
    152.     cmp byte ptr [eax],68H
    153.     jne @f
    154.     push ExitFlags
    155.     push CALLBACK_DATA.Parameter[ecx]
    156.     push eax
    157.     push ImageBase
    158.     Call CALLBACK_DATA.Routine[ecx]
    159. @@:
    160.     ret
    161. SearchCallbackInternal endp
    162.  
    163. ; +
    164. ; Ищет инструкцию Push XXXX для ссылки сканируя таблицу базовых поправок.
    165. ;
    166. LdrSearchPushReferenceInRelocationTable proc ImageBase:PVOID, Ip:PVOID, CallbackRoutine:PVOID, CallbackParameter:PVOID
    167.     lea ecx,CallbackRoutine
    168.     Call _$_SearchCallback
    169.     invoke LdrEnumerateFixups, ImageBase, Ip, Eax, Ecx
    170.     ret
    171. LdrSearchPushReferenceInRelocationTable endp
    172.  
    173. ; +
    174. ; Ищет строку ASCII "LDR: Tls Found in %wZ at %p",LF
    175. ; [Сообщение может отличаться в версиях.]
    176. ;
    177. LgSearchMessage proc uses edi ImageBase:PVOID, Message:PVOID
    178. Local ImageHeader:PIMAGE_NT_HEADERS
    179.     mov edi,ImageBase
    180.     invoke LdrImageNtHeader, Edi, addr ImageHeader
    181.     test eax,eax
    182.     mov ecx,ImageHeader
    183.     jnz Exit
    184.     add edi,IMAGE_NT_HEADERS.OptionalHeader.BaseOfCode[ecx]
    185.     mov ecx,IMAGE_NT_HEADERS.OptionalHeader.SizeOfCode[ecx]
    186.     cld
    187.     mov al,'L'
    188.     mov edx,Message
    189. @@:
    190.     repne scasb
    191.     jne @f
    192.     cmp dword ptr [edi]," :RD"
    193.     jne @b
    194.     cmp dword ptr [edi + 4]," slT"
    195.     jne @b
    196.     cmp dword ptr [edi + 2*4],"nuoF"
    197.     jne @b
    198.     dec edi
    199.     xor eax,eax
    200.     mov dword ptr [edx],edi
    201.     jmp Exit
    202. @@:
    203.     mov eax,STATUS_NOT_FOUND
    204. Exit:
    205.     ret
    206. LgSearchMessage endp
    207.  
    208. _$_LgSearchCallback:
    209.     GET_CURRENT_GRAPH_ENTRY
    210. LgSearchCallback proc ImageBase:PVOID, Ip:PVOID, Message:PVOID, ExitFlag:PBOOLEAN
    211.     mov eax,Message
    212.     mov ecx,Ip
    213.     mov edx,ExitFlag
    214.     mov dword ptr [eax],ecx
    215.     mov byte ptr [edx],1
    216.     xor eax,eax
    217.     ret
    218. LgSearchCallback endp
    219.  
    220. Entry proc
    221. Local Message:PVOID
    222.     assume fs:nothing
    223.     mov eax,fs:[TEB.Peb]
    224.     mov eax,PEB.Ldr[eax]
    225.     mov eax,PEB_LDR_DATA.InLoadOrderModuleList.Flink[eax]
    226.     mov eax,LDR_DATA_TABLE_ENTRY.InLoadOrderModuleList.Flink[eax]
    227.     mov ebx,LDR_DATA_TABLE_ENTRY.DllBase[eax]
    228.     invoke LgSearchMessage, Ebx, addr Message
    229.     test eax,eax
    230.     lea ecx,Message
    231.     .if Zero?
    232.     Call _$_LgSearchCallback
    233.     invoke LdrSearchPushReferenceInRelocationTable, Ebx, Message, Eax, Ecx
    234.     .if !Eax
    235.     int 3
    236. ; В случае успеха Message будет содержать указатель в LdrpInitializeTls().
    237. ; Далее можно найти её начало(..\Belong\Ip.asm, SearchRoutineEntry()).
    238.     .endif
    239.     .endif
    240.     ret
    241. Entry endp
    242. end Entry
    Перекрёстный линк, должно быть интересно автору http://www.wasm.ru/forum/viewtopic.php?id=35894
     
  3. kaspersky

    kaspersky New Member

    Публикаций:
    0
    Регистрация:
    18 май 2004
    Сообщения:
    3.006
    Клерк рулит, впрочем, как и всегда. Все очень круто.

    > Разрушаем указатель в GlobalNameRef, предварительно
    > сохранив его для последующего восстановления.
    От себя добавлю как решил проблему восстановления указателей. Установка старшего бита заставляет систему лезть туда, куда она сама себя не пускает, выбрасывая исключение. А для восстановления оригинального значения мы просто тупо сбрасываем старший бит взад. Ничего запоминать нигде не надо.

    с глубоким почтением к клерку-сан
    мыщъх
     
  4. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    kaspersky
    Выше очень обобщенное описание, подробности в аттаче. Восстанавливать не нужно, этим занимается двиг изменяя целевой сегмент посредством перезагрузки селекторов. Иначе будет не возможной обработка для нескольких потоков.
     
  5. kaspersky

    kaspersky New Member

    Публикаций:
    0
    Регистрация:
    18 май 2004
    Сообщения:
    3.006
    Clerk
    с потоками согласен. но там где их заведомо нет (или они заведомо не тронут данную ячейку) - такой способ вполне прокатывает. к тому же даже если мы не восстанавливаем ячейку, а "эмулируем" операции чтения/записи в движке, то нам надо где-то хранить оригинальное значение. почему бы не в самой переменной, установив старший бит в единицу?

    ЗЫ. аттач не смотрел. сейчас курить буду
     
  6. J0E

    J0E New Member

    Публикаций:
    0
    Регистрация:
    28 июл 2008
    Сообщения:
    621
    Адрес:
    Panama
    kaspersky по моему слишком быстро сдался, как раз при наличие нескольких тредов его способ позволяет проще отвязаться от контекста, а для поддержки реентерабельности и подавно. С другой стороны, он не для ядра, и может быть эксплуатирован (теоретически).

    ЗЫ аттач тоже не смотрел. интересно для кого здесь пишет Clerk, посту более 4х месяцев и 40 скачиваний :dntknw:
     
  7. n0name

    n0name New Member

    Публикаций:
    0
    Регистрация:
    5 июн 2004
    Сообщения:
    4.336
    Адрес:
    Russia
    40 скачиваний это очень много.
    Скорее всего лишь пара оказалось удачных )
     
  8. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Я уделил этой технике очень много времени и считаю её весьма кошерной.
    kaspersky
    Уже говорил что используется гибкая манипуляция селекторами, точнее подмена сегмента, база которого вычисляется как разность смещений двух сегментов. После записи в переменную никакие манипуляции с ней не выполняются. На вирустеке описан матан подробно.
    J0E
    Для ядра аналогично, там есть некоторые нюансы, но сути это не меняет.
    n0name
    Если вы поняли смысл тогда респект.
     
  9. J0E

    J0E New Member

    Публикаций:
    0
    Регистрация:
    28 июл 2008
    Сообщения:
    621
    Адрес:
    Panama
    Замечание про ядро относится не оригинальной технике, а к установке старшего бита, но это мелочи.

    Кошерная, да, определение в точку. control flow меняется, а машинный код нет. Бороться с этим, как говорится, a real pain in the ass. Имплементация может оказаться довольно сложной не только для реализации (простите за тавтологию) но и для понимания, вот я и удивлен малым количеством скачиваний, может быть многие сами давно такое сделали и им уже не интересно? :)
     
  10. n0name

    n0name New Member

    Публикаций:
    0
    Регистрация:
    5 июн 2004
    Сообщения:
    4.336
    Адрес:
    Russia
    Clerk
    ну когда разжевано, да еще и сорц есть, трудно не понять :)
    Немного напрягает термин "захват", всё же чаще юзается "перехват" имхо.
     
  11. GriD

    GriD New Member

    Публикаций:
    0
    Регистрация:
    29 дек 2009
    Сообщения:
    13
    n0name

    Врятли:)

    J0E

    Для людей, я думаю.

    Clerk

    "Техника" весьма интересная, правда, можно еще развить. На первый взгляд - раскручивается эвристиком нода, это раз. Возможны(хотя еще проверю) всякие глюки в семерке, это два.

    Респект тебе, за труды. Но старайся быть впереди планеты всей, мой тебе совет - раскручивай х64 семерку, и не исчи зомбу. Того зомбы уже нет, а какой щаз - я думаю, ты не захотел бы его таким найти.
     
  12. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    GriD
    К эмуляции это отношения не имеет. В w7 глюков нет. Двиг откатан на 7-ке. Могут быть проблемы с примерами, но только потому, что у меня XP и лень лезть олей в модуля от 7, в частности это касается текстовых строк.
     
  13. Velheart

    Velheart New Member

    Публикаций:
    0
    Регистрация:
    2 июн 2008
    Сообщения:
    526
    У меня перед новым годом на свежую семерку залелез зверег, который не давал никакие дрова грузить, а еще вешал все при запуске скайп и айсику, ну т.е. даже мышь не шевелилась, буквально немного поковырялся, нашел в в одной из LoadImageNotifyRoutine что-то типа 00000001 или 00000010, и сразу вспоинил про этот пост =), а потом срочно понадобился скайп, и пришлось винду переустанавливать, жаль, что поковырять больше не удалось..
     
  14. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Velheart
    VOID.
     
  15. J0E

    J0E New Member

    Публикаций:
    0
    Регистрация:
    28 июл 2008
    Сообщения:
    621
    Адрес:
    Panama
    Для людей... и я думаю, кто по 2 раза качал, кто качал, но не читал, кто читал, но не понял. "пара удачных". Пол темы прально читать меж строк:-\ Суть басни не в НОДе а в концепте и подходе (:с:)

    И кстати, Зомба... 5 сек ;) не хочу спрашивать, что с ним стало, и без того вижу, это рок >:
     
  16. J0E

    J0E New Member

    Публикаций:
    0
    Регистрация:
    28 июл 2008
    Сообщения:
    621
    Адрес:
    Panama
    Жаль, что удалил, мож оно реально по тем адресам и было.
     
  17. Velheart

    Velheart New Member

    Публикаций:
    0
    Регистрация:
    2 июн 2008
    Сообщения:
    526
    Виндбг не видел по ним ничего, это первое, что пришло в голову)

    ну всмысле в указателе на один из калбэков, или я чего-то не понял?
     
  18. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Velheart
    Я думал вы имели ввиду возвращаемое значение, а не ссылку на калбэк. У виндбг есть проблемы с отображением памяти, не удивительно если он криво чтото показал.
    J0E
    Иди флуди в другой топик. Заладил нод, нод.. да гуан ваш нод.
     
  19. kaspersky

    kaspersky New Member

    Публикаций:
    0
    Регистрация:
    18 май 2004
    Сообщения:
    3.006
    малява модераторам
    зачем клерка забанили?! выражаю решительный протест. интересный же человек. с кучей свежих идей. без него тут совсем скучно. не по дзенски это.
     
  20. linuxmodule

    linuxmodule New Member

    Публикаций:
    0
    Регистрация:
    15 дек 2009
    Сообщения:
    25
    Clerk
    ХЫ.. забанен второй раз (на моей памяти) :)