четверг, 31 марта 2011 г.

Храните деньги на депозите в банке

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


Депозиты в РБ делятся на три основные категории: до востребования, срочные и условные. 
Под условным понимается депозит, по которому сумма вклада с начисленными процентами возвращается вкладчику при наступлении/ненаступлении определенного в заключенном договоре обстоятельства (события). Пока применяется для частных лиц достаточно редко.

По вкладам до востребования конкретный срок хранения не устанавливается. Это самый простой и удобный вклад. На него можно вносить, в том числе пополнять, и с него можно снимать любые суммы и в любое удобное для вас время. Такой вклад есть во всех банках, он открывается в любой валюте, с которой может работать банк, деньги на таком счёте доступны всегда. Но и заработать не удастся – на таких вкладах крайне низкая процентная ставка. Такой вклад подходит тем, кто просто не хочет хранить деньги дома, но которые могут понадобиться в любой момент, либо для проведения разовых расчетных операций (внес и вскоре снял/перевел).

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

В случае, если Вы досрочно забираете средства со срочного депозита, проценты по вкладам обычно начисляются по ставке «до востребования», т.е. минимальной. Однако некоторые банки, стремясь повысить привлекательность своей депозитной линейки, вводят вклады, в условиях которых предусмотрены повышенные, по сравнению со ставкой вклада «до востребования», проценты при досрочном снятии. Это может быть удобно, если вероятность досрочного изъятия Вами депозита крайне мала, но все же вероятна.

Если же вы забыли вовремя забрать деньги, то банк переводит ваши деньги на счёт до востребования или продлевает (пролонгирует) действие договора. Процентный доход за основной период начисляется в полном объеме согласно договору.
Оговоримся, что нижеприведенные деления депозитов на практике условно, т.к. часто встречаются вклады, сочетающие «разнородные» характеристики. 
Срочные вклады делят на сберегательные и накопительные. Главное их отличие – в возможности или невозможности пополнения.
Сберегательный - это собственно традиционный вклад, с минимумом функций, в том числе в ряде случаев с процентов.
Если Вам не принципиально получать дополнительный доход ежемесячно, можете открыть сберегательный депозит. Как правило, по нему внесение денег в период действия договора не предусмотрено. Однако он – очень удобный способ сберечь свои накопления, не растратив их на мелочи. Другими словами, вы приносите в банк определенную сумму, заключаете договор, выбираете вклад с удобным режимом выплаты процентов (доходный – помесячно, поквартально; сберегательный – в конце срока, а бывает, но не в РБ, авансом!), но денег на счет больше не вносите.

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

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

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

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

В Беларуси ставка процентов на сумму пополнения вклада, как правило, не отличается от основной. Однако в депозитном договоре банк может прописать различные ограничения, которые могут помешать вкладчику максимально эффективно пользоваться накопительным счетом.
Во-первых, это могут быть ограничения по сумме общего вклада (то есть счет можно пополнять до определенного уровня или минимальной сумме пополнения).
Во-вторых, могут быть ограничения по срокам. Например, вклад разрешается пополнять только первые полгода или нельзя пополнять в последний месяц и т.п. Со стороны банков такое ограничение вполне логично: им невыгодно выплачивать клиенту высокий процент как по годовому вкладу за сумму, которая пролежала месяц.

Существуют также пополняемые депозиты с возможностью частичного изъятия средств без потери процентов. Такие счета можно пополнять, однако размер минимального взноса и сроки пополнения чётко оговариваются в договоре. Деньги можно снимать, но сумма средств на счёте не должна опускаться ниже оговоренного порога – неснижаемого остатка. На подобных счетах процентная ставка чуть ниже, чем на классических срочных депозитах.


Стоит еще упомянуть несколько обособленных видов вкладов.

Расчетные (как правило, с выпуском банковской дебетовой карточки). Для желающих сохранить контроль над размещенными средствами. Такие вклады также пополняемые, кроме этого в рамках таких вкладов обычно предлагается периодическая (к примеру, ежемесячная) выплата процентов на счет или пластиковую карту и возможность свободно использовать средства вклада с одним условием: на счете всегда должна оставаться сумма в размере особо оговоренного минимального остатка, в противном случае ставка автоматически снижается.

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

Специализированные вклады, предназначенные для отдельных категорий клиентов — для ветеранов, пенсионеров, детей, работников определенных предприятий, клиентов банка.

Источник http://benefit.by/page/show/articles/21.

понедельник, 28 марта 2011 г.

Для чего нужен ипотечный калькулятор

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

На данный момент есть калькуляторы, которые помогут рассчитать максимальную сумму банковского кредита, учитывая совокупные ежемесячные доходы клиента и его семьи. Существуют также и другие виды ипотечных калькуляторов, с помощью которых рассчитываются выплаты банку-кредитору, исходя из рыночной стоимости покупаемой недвижимости, а также величины первоначального взноса. Расчет платежей ипотечного кредита можно осуществлять или по аннуитетной схеме, или по дифференцированной (стандартной). Аннуитетная схема имеет место тогда, когда кредит погашается равными платежами в течение всего срока выплаты кредита. Платежи состоят как из выплат самого тела кредита, так и процентов, начисленных банком за пользование ипотекой. В России именно аннуитетные платежи стали наиболее популярными и распространенными среди населения. Они являются достаточно удобными при планировании бюджета семьи заемщика, поскольку представляют собой одинаковый по размеру платеж каждый месяц. Стандартная или дифференцированная форма – это такой вид платежа, при котором само тело кредита заемщик выплачивает одинаковыми частями во время всего кредитного срока, а проценты банку-кредитору насчитываются на остаток суммы задолженности, которая каждый месяц уменьшается. Поэтому необходимо учесть, что если в самом начале погашения кредита сумма ежемесячных аннуитетных выплат будет меньше, чем сумма дифференцированных платежей, то со второй половины кредитного срока платеж по дифференцированной схеме значительно уменьшится. В итоге получится, что если заемщик выбрал для себя аннуитетную схему расчета, то он заплатит банку-кредитору большую денежную сумму, чем тот заемщик, который рассчитывается по стандартной схеме.

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

Благодаря использованию ипотечного калькулятора, Вы имеете прекрасную возможность оценить не только быстро, но и наглядно денежные затраты, которые вам предстоят во время приобретения жилья по ипотеке.
Расчет ипотеки с помощью кредитного калькулятора. http://russia.allbanks.org/info/credits.html



При подготовке были использованы материалы сайта http://www.creditsbrf.ru/articles/013.htm


пятница, 25 марта 2011 г.

С++ ООП. Проектирование сетевого клиента.


Поскольку мы уже немного освоились с перехватом сетевого трафика, с тем как формируются пакеты передаваемые по сети и программировании сетевых приложений, то пора уже приступать к важной части – проектированию приложения. И если с логикой работы программы у нас не возникает затруднений потому, что достаточно пары условий и действий по отправке-приему сообщений, то вот проблемы с раздутием кода из-за появления временных переменных и прочего непотребного хлама начинают уставать глаза и напрягаться мозг. Выход есть. Спроектировать приложение с учетом парадигмы ООП, которая нам поможет и код сделать понятным, да и ООП научиться применять на практике.
Но с чего нужно начать? Куда это ООП прикладывать или приписывать? Как мы уже видели, логика работы с сетью однозначна и не требует улучшений. А вот с самими пакетами дела обстоят намного хуже. Постоянно приходится что-то с ними делать, то разбирать на части, выделяя заголовок или тело, то сравнивать с чем-то. Вот тут-то и начинается простор для проектировщика.
Что на текущий момент нам уже известно:
1)      Приходящие и отправляемые пакеты – это набор символов (в С++ их удобно хранить в массивах).
2)      Обычно такие сообщения имеют заголовок 4 символа (байта).
3)      Тело таких сообщений может быть разной длины.



Не забудем, что еще у нас есть ID клиента для сетевой и его тоже нужно где-то постоянно хранить.
Теперь давайте приблизительно набросаем, что необходимо для простой и незамысловатой работы с сетевыми пакетами:
1)      Длина всего сообщения
2)      Заголовок и его длина.
3)      Тело сообщения и его длина.
4)      ID сетевого клиента и его длина.

Поскольку ООП предполагает принцип разделения данных и методов и сокрытия внутренних механизмов от пользователя (инкапсуляция), то будем исходить из того, что данные будут недоступны напрямую, а для того чтобы получить значение того или иного нужного нам свойства объекта будет использовать методы.
В результате можно предположить, что неплохо было бы обзавестись следующими методами для приходящих пакетов:
1) Выделение из полученного пакета заголовка и тела, заполнение полей отвечающих за длины заголовка и тела.
2) Установка, получение длины сетевого пакета.
3) Установка, получение заголовка пакета
4) Установка, получение длины заголовка пакета.
5) Установка, получение тела пакета
6) Установка, получение длины тела  пакета.
7) Установка, получение ID пакета
8) Установка, получение длины ID пакета.

Что касается формирования отправляемого пакета данных, но свойства и методы не сильно отличаются от перечисленных выше.

Для примера разберем содержимое заголовочного файла rcvpckt.h, в котором объявим все, что необходимо для работы с приходящими пакетами:

const unsigned int mx_buff = 2048+2;
const unsigned int hdrSz = 4+1;
const unsigned int bdySz = mx_buff-hdrSz;

class rcvPckt
{
    char id[hdrSz];
    int idLen;
    char header[hdrSz];
    char bdy[bdySz];
    int hdrLen;
    int bdyLen;


public:
    char rPckt[mx_buff];

    rcvPckt()
    {
        hdrLen = hdrSz-1;
    }

    void setRcvdPcktLen(int len)
    {
         bdyLen = len - hdrLen+1;
    }

    int getRcvdPcktLen()
    {
        return hdrLen + bdyLen;
    }

    char *getRcvdPckt()
    {
        return &rPckt[0];
    }

    void setHdr(char *value, unsigned int len);

    char *getHdr()
    {
        return &header[0];
    }

    int getHdrLen()
    {
        return hdrLen;
    }

    void setBdy(char *value, unsigned int len);

    char *getBdy()
    {
        return &bdy[0];
    }

    int getBdyLen()
    {
        return bdyLen;
    }

    void setId(char *value, unsigned int len);

    char *getId()
    {
        return &id[0];
    }

    int getIdLen()
    {
        return idLen;
    }

    void fillRcvdPckt(char *value, unsigned int len);

};

И заголовочное файла sndpackt.h:

const unsigned int mx_buff = 2048+2;
const unsigned int hdrSz = 4+1;
const unsigned int bdySz = mx_buff-hdrSz;

class sndPckt
{
    char sPckt[mx_buff];
    char header[hdrSz];
    char bdy[mx_buff - hdrSz];
    int hdrLen;
    int bdyLen;

public:

    sndPckt()
    {
        hdrLen = hdrSz-1;
    }

    void setHdr(char *value, unsigned int len);

    char *getHdr()
    {
        return &header[0];
    }

    int getHdrLen()
    {
        return hdrLen;
    }

    void setBdy(char *value, unsigned int len);

    void setBdyNoth();

    char *getBdy()
    {
        return &bdy[0];
    }

    int getBdyLen()
    {
        return bdyLen;
    }

    char *sendPckt();

   
    int sendPcktLen()
    {
        return hdrLen + bdyLen;
    }
};

Теперь все манипуляции с сетевыми пакетами должны стать более наглядными и простыми для чтения. Теперь можно переходить к этапу реализации методов для созданных классов.

пятница, 18 марта 2011 г.

Алгоритм изменения Id сетевого клиента. Воплощение в коде.


Почти со всеми вопросами, касающимися алгоритма получения и обработки Id клиента сетевой игры мы разобрали. Пора перейти непосредственно к воплощению задуманного в коде. Но постойте. Кажется, что мы что-то упустили из виду. Так и есть. Ведь все наши рассуждения относительно того, как происходит процесс преобразования приходящей информации, строились исходя из того, что работать будем не с байтами, а с частями этих байтов. Давайте вспомним как все это выглядит в действительности в нашей программе сейчас. Приходит сообщение из 8 байт и мы записываем его в массив.
char ans1[] = { 0xCF, 0xCF, 0xCF, 0xCF, 0x01, 0x02, 0x30, 0x40, 0};
Для примера, приведен массив, в котором хранится присылаемый сервером пакет вместе с заголовком. Значит заголовок:
0xCF, 0xCF, 0xCF, 0xCF
Тело сообщения:
0x01, 0x02, 0x30, 0x40
Но вот беда, наш алгоритм рассчитан на работу с каждой отдельной шестнадцатеричной единицей. А давайте попробуем написать собственную функцию, которая будет из принятого массива 4 байт создавать новый массив размером 8 ячеек, в каждой из которой будет хранится одно шестнадцатеричное число. То есть результат предыдущего тела сообщения должен предстать в виде:
0x0, 0x1, 0x0, 0x2, 0x3, 0x0, 0x4 , 0x0.
Опять же значения каждого числа записаны в шестнадцатеричном виде.
Чтобы была понятна сама схема разбора на составные части, попробуем представить этот процесс для одного числа.
0х01 = 1 * 16 0 + 0 * 16 1 = 1
0х40 = 0 * 16 0 + 4 * 16 1 = 64
Для того чтобы сделать все тоже самое, но только обратно, то есть из десятичного числа получить 16-чное:
1 = 1 / 16 1 = 0 (остаток 1) – это первое 16-чное значение
1 = 1 / 16 0 = 1 (остаток 0) – это второе 16-чное значение

64 = 64 / 16 1 = 4 (остаток 0) – это первое 16-чное значение
0 = 0 / 16 0 = 0 (остаток 0) – это второе 16-чное значение

Вот что получилось, если сделать функцию, для обработки массива любого размера:
char *Decod(char *value, unsigned int len)
    {
        char *dec = new char[len * 2];
        for (unsigned int i = 0, j = 0; i < len*2; i += 2, j++)
        {
            dec[i] = (unsigned char)((unsigned char)value[j] / 16);
            dec[i + 1] = (unsigned char)((unsigned char)value[j] % 16);
         }
    }
Видно, что подавать на вход мы должны массив и его размер, а на выходе будет указатель на массив, который размером в два раза больше. И только после этого можно будет обрабатывать каждый отдельный элемент нового массива согласно выведенного нами алгоритма изменения Id. А вот и этот алгоритм, который мы так усердно расписывали в excel:

if ((value[0] == 0) || (value[0] == 8))  { value[0] += 7; }
        else
        if ((value[0] == 1) || (value[0] == 9)) { value[0] += 5; }
        else
        if ((value[0] == 2) || (value[0] == 10)) { value[0] += 3; }
        else
        if ((value[0] == 3) || (value[0] == 11)) { value[0] += 1; }
        else
        if ((value[0] == 4) || (value[0] == 12)) { value[0] -= 1; }
        else
        if ((value[0] == 5) || (value[0] == 13)) { value[0] -= 3; }
        else
        if ((value[0] == 6) || (value[0] == 14)) { value[0] -= 5; }
        else
        if ((value[0] == 7) || (value[0] == 15)) { value[0] -= 7; }


        if ((value[1] == 0) || (value[1] == 1) || (value[1] == 4) || (value[1] == 5))     { value[1] += 10; }
        else
        if ((value[1] == 2) || (value[1] == 3) || (value[1] == 6) || (value[1] == 7))     { value[1] += 6; }
        else
        if ((value[1] == 8) || (value[1] == 9) || (value[1] == 12) || (value[1] == 13))   { value[1] -= 6; }
        else
        if ((value[1] == 10) || (value[1] == 11) || (value[1] == 14) || (value[1] == 15)) { value[1] -= 10; }


        if ((value[2] == 0)  || (value[2] == 1)  || (value[2] == 4) || (value[2] == 5) || (value[2] == 8) ||
            (value[2] == 9)  || (value[2] == 12) || (value[2] == 13)) { value[2] += 2; }
        else
        if ((value[2] == 2)  || (value[2] == 3)  || (value[2] == 6) || (value[2] == 7) || (value[2] == 10) ||
            (value[2] == 11) || (value[2] == 14) || (value[2] == 15)) { value[2] -= 2; }


        if ((value[3] == 0) || (value[3] == 4)) { value[3] += 11; }
        else
        if ((value[3] == 1) || (value[3] == 5)) { value[3] += 9; }
        else
        if ((value[3] == 2) || (value[3] == 6)) { value[3] += 7; }
        else
        if ((value[3] == 3) || (value[3] == 7)) { value[3] += 5; }
        else
        if ((value[3] == 8) || (value[3] == 12)) { value[3] -= 5; }
        else
        if ((value[3] == 9) || (value[3] == 13)) { value[3] -= 7; }
        else
        if ((value[3] == 10) || (value[3] == 14)) { value[3] -= 9; }
        else
        if ((value[3] == 11) || (value[3] == 15)) { value[3] -= 11; }


        if (((value[7] >=0 ) && (value[7] <=3)) || ((value[7] >= 8 ) && (value[7] <=11))) { value[7] += 4; }
        else
        if (((value[7] >= 4) && (value[7] <= 7)) || ((value[7] >= 12) && (value[7] <= 15))) { value[7] -= 4; }

Где массив value[] это то, что должно у нас появиться после работы функции Decod.

А что же дальше? После обработки каждого отдельного шестнадцатеричного значения, нужно будет свернуть 8 шестнадцатеричных чисел обратно в 4 байта. И в этом нам поможет функция:
char *Encod(char *value, unsigned int len)
    {
        char *en = new char[len/2];
        for (unsigned int i = 0, j = 0; i < len; i += 2, j++)
        {
            en[j] = (unsigned char)((unsigned char)(value[i] * 16) + (unsigned char)value[i + 1]);
            //Console.WriteLine(en[j]);
        }

        return en;
    }
Здесь все происходит ровно наоборот, если сравнивать с функцией Decod, то есть создаем из пары 16-чных чисел одно десятичное.

Пора собирать все это в единый монолит и лишь надеяться на очередное чудо.

Исходный код клиента, который принимает, обрабатывает ID и отправляет серверу.
Для наглядности включена функция вывод массива на экран, которая сначала показывает значения ID пришедшие с сервера в количестве 8 штук (то есть те самые 8 16-чных значений, после разбиения 4 байтов на куски), а затем этот же ID после «магических пассов» и до отправки на сервер.

Маленькое чудо своими руками мы сотворили.

среда, 16 марта 2011 г.

Алгоритм изменения Id сетевого клиента.


Как уже нам стало известно, для начало общения необходимо принять от сервера набор из 8 шестнадцатеричных значений (или по-простому, 4 байта), которое является уникальным идентификатором сетевого клиента - Id, затем магическим образом изменив их, нужно отправить этому серверу. Для того чтобы поближе ознакомится с эталоном принимаемого Id и отправляемого, мы уже реализовали сервер и попробовали отправлять заранее известные комбинации значений, а затем сохранять для изучения ответы сетевого клиента. Чтобы максимально упростить задачу, отправим всего 16 сообщений и проследим за их метаморфозами, а при удачном стечении обстоятельств, узнаем какой алгоритм изменения был использован.
Вот эти 16 сообщений отправленные нашим сервером и ответы, которые прислал настоящий клиент:


Улов настоящего охотника за сетевыми пакетами богат. Пора сворачивать сети и начинать разбирать улов. Первое, что бросается в глаза, это то, что мы работать должны не с байтами, а с 16-чными числами, которых получается 8 штук. Из этих 8, как видно изменяются первые 4 и последнее. А 5, 6, 7 не изменяются. Ну что, можно считать, что полдела сделано.
Дальше запишем все изменения, выделив столбец для каждого 16-чногочисла, группировку делаем по 2 строки, первая строка – это поданные на вход числа, вторая строка – это принятые от сетевого клиента числа:



В таком виде ничего внятного сказать нельзя о том, как изменяется Id. Попробуем перемешать всю эту кашу и подать с другим соусом.



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

А вот и вторая половина дела сделана, осталось только все это воплотить в коде.

воскресенье, 13 марта 2011 г.

Разбираем процесс сетевого общения в деталях. Эмулируем сервер.


Наше дело застопорилось и видимо продвигаться дальше не хочет. Все возможные варианты были перебраны, но присылаемый ответ от сервера нам так и не удалось преобразовать для последующей отправки обратно. Видно уж очень хитрый алгоритм применяется. Как же быть? В нашем случае не нужно рвать волосы на голове или груди, не нужно брать волшебный бубен и исполнять тайный танец. А все потому, что в нашем распоряжении имеется парочка трюков. Итак, приступим к вскрытию этого хитрого алгоритма преобразования полученного сообщения – идентификатора сетевого клиента, который назовем для краткости Id. Есть два пути:
1)      Для этого нам понадобится тысяча часов неустанного наблюдения за посылаемыми пакетами, запись их в экселевкий файл, выделение всех уникальных сообщений, создание математической формулы для расчета преобразования.
2)      Создание собственного сервера, а затем посыл данных каких мы хотим, чтобы узнать, как все-таки отвечает на них клиент.
Ну что, выбираем вариант №2?

Немного поколдовав над кодом программы и немного его видоизменив, получаем уже не клиент, а сервер который будет вместо настоящего сервера игры получать и отправлять данные, общаясь с настоящим клиентом. То есть задумка такая:
1)      Запускаем собственный сервер, который будет ожидать от настоящего клиента сообщения «EFEFEFEF».
2)      Посылаем в ответ «CFCFCFCF» + некоторое сообщение («Х»).
3)      Смотрим, как на это сообщение отреагирует клиент и что пришлет нам.
Так что вместо «Х»? Ну, поскольку, «Х» это кусочек, который имеет размер 4 байта, то значит нужно отсылать все возможные комбинации этих 4 байтов. То есть:
0 0 0 0
0 0 0 1
0 0 0 2
0 0 0 3
…
0 0 0 255
0 0 1 0
0 0 1 1
…
0 0 255 255
0 1 0 0
…
255 255 255 254
255 255 255 255

Солидное количество информации. Количество пакетов, которые нужно отправить и принять умопомрачительное. Если еще учесть, что это потом нужно будет все записать, то волосы встают дыбом.
Предлагаю разбить все общение с клиентом нашего сервера на мини-тесты. Другими словами будем следить за изменениями в шестнадцатеричной системе и изменять за один раз на одну шестнадцатеричную единицу. Что-то похожее на это:
00 00 00 00
00 00 00 01
00 00 00 02
…
00 00 00 0D
00 00 00 0F

00 00 00 10
00 00 00 20
…
00 00 00 F0

00 00 01 00
00 00 02 00
…
00 00 0F 00

…
10 00 00 00
20 00 00 00
…
F0 00 00 00

Соответственно отследить 16 разных сообщений проще, чем 4 294 967 296 повторов. И будем надеяться на чудо, что нам повезет, и мы увидим хоть что-то похожее на общую формулу изменения Id.
На практике получается, что нужно запустить цикл с повтором 15 и изменять:
1)      Для увеличения первой шестнадцатеричной единицы будем на каждом шаге прибавлять 1.
2)      Для увеличения второй шестнадцатеричной единицы будем на каждом шаге прибавлять 16.
Все это нужно проделать с каждым из 4 байт.

Пробная версия программы.

Начинаем тестирование. Запускаем NPA в режиме захвата локально траффика. Запускаем наш сервер. Запускаем клиент, пытаемся подключиться. Но неожиданно обнаруживаем, что в ответ на 16 пакетов с разными сообщениями, нам в ответ клиент прислал всего лишь одно. Чувство огорчения пусть не сильно нас тревожит. Ведь нам удалось подделать сервер и заставить думать клиент, что он общается с настоящим сервером. Это большая победа. И теперь осталось всего-навсего вручную, без всяких циклов послать 16 х 16 сообщений и записать все результаты в табличном виде.
Пробная версия программы №2.


Первый результат уже получен, дело за малым. Увеличивать каждый раз на шестнадцатеричную единицу отсылаемое сообщение и фиксировать результат.
Итак, первая пара готова.
Послали: CFCFCFCF00000000 .
Получили: CACACACA7A2B0004 .

Ну и напоследок пара замечаний:
Не стоит волноваться, если ваша программа-сервер начнет занимать 40 – 60 % мощности процессора – это нормально для консольного сервера.
Переменная ans1len нужна, для того чтобы хранить размер передаваемой строки по сети, если же будет использоваться strlen (ans1[]), то размер будет определен неправильно, поскольку в строке имеются спец символы, в частности {0xCF, 0xCF, 0xCF, 0xCF, 0x00, 0x00, 0x00, 0x00, 0}. Это означаем, что после измерения длины строки с помощью функции strlen, мы получим неправильную длину – 4 символа. Ведь 0x00 это ноль, а ноль как известно – признак конца строки.

четверг, 10 марта 2011 г.

Разбираем процесс сетевого общения в деталях. Эпизод 2.


Наших знаний пока что хватило на то, чтобы связаться с сервером и получить хоть что-то от него вразумительное в ответ. Теперь же, чтобы продвигаться дальше нужно разузнать, что все-таки отвечает сервер, как это обрабатывать и какой запрос посылать следующим.
Как уже нам известно сервер в ответ на приветствие должен прислать «CFCFCFCF» + Х. В след за этим нужно послать запрос «CACACACA»+ Х. Допустим что «Х» это одно и то же. Попробуем выделять кусок после «CFCFCFCF» и отправлять его, только в начало поставив «CACACACA».
Для удобства заведем массив header[5], куда будем складывать первые 4 полученных байта. Поскольку уже видно, что каждое сообщение передаваемое от сервера к клиенту и обратно имеет постоянную часть и часть, которая может изменяться. И, соответственно, каждый раз когда приходит сообщение будем смотреть на его заголовок, а уж потом разбираться что будем с ним делать.
В результате должно получиться что-то вроде:

Прежде чем запустить пример, нужно поставить NPA в режим захвата локального трафика. Ну что, попробуем?
Ответ сервера на приветствие:

Пробуем послать тоже самое, изменив заголовок:

Ответ один и тот же:


И так повторяя раз за разом, можно убедиться, что исходное предположение о том, «что пришло в теле сообщения то и отправляем серверу» неверно. Нам постоянно приходят сообщения с заголовком «DF DF DF DF» + X + Y. Думаю, что нетрудно заметить, что X везде одинаковый. В нашем примере это «13 E0 58 9E».

Посмотрим за процессом общения настоящего клиента и сервера. Запускам клиент игры. Подключаемся. Стреляем. Отключаемся. Что нас интересует? Прокручиваем весь список отправленных сообщений до конца. И видим, что общение всегда заканчивается сообщением с заголовком «DF DF DF DF». Только этот пакет посылает клиент. Получается, мы узнали две важных вещи.
1)      «DF DF DF DF» - это заголовок пакета, которым завершается общение между клиентом и сервером. Послать его может и клиент, и сервер.
2)      «X» - это своеобразный кусочек, который отправляется сервером и служит уникальным идентификатором для клиента. Как это определить? Очень просто – запустить процесс подключения и отключения настоящего клиента игры раз 100 и проследить за тем, что приходит в сообщении от сервера после заголовка «CACACACA» и сравнить с тем, что отравляется клиентом в сообщении, которым все завершается, то есть после «DF DF DF DF». Совпадает все 100 раз. Итак, это уникальный идентификатор клиента сетевой игры.

Поскольку это важная часть процесса общения, то создадим переменную для хранения уникального идентификатора (Id).

Но так и остался открытым вопрос, что все-таки нужно отправлять серверу, после получения Id?