"1 "1 DLL TUTORIAL Spis Treści 1. Tworzenie pustego pliku DLL 2. Rejestracja Konta na serwerze 3. Logowanie 4. Wylogowanie 5. Tokeny 6. Upload
"2 "2 1. TWORZENIE PUSTEGO PLIKU DLL Do napisania dll potrzebujesz: 1.Visual Studio C# 2.dodatek do Firefoxa "Live Http Header" Jeśli ktoś zaczyna zabawę pokażę jak stworzyć pustą dll Wszystko pokaże na załączonych obrazkach poniżej. Wybieramy Class Library. W polu Name i Solution name wpisujemy TestowaClient, ważne jest aby było "Client". Gdy dodamy YgoowCore.dll do Referencji, dodajemy using ygoow.mailheaders; using ygoow.mailclients; using ygoow; i zmieniamy "namespace TestowaClient" na "namespace ygoow.mailclients" tak jak na obrazkach
"3 "3
"4 "4 Pustą dll`kę zapisujemy. Po tej czynności mamy przygotowany pusty plik DLL jako podstawa do dalszych prac. Tak utworzony plik DLL mozna pobrac pod adresem : http://ygoow.com/dll/pusty_projekt_nowej_dll/skrzynkaclient.zip
"5 2. REJESTRACJA KONTA NA SERWERZE "5 Aby móc zakładać nowe konta w YG, będziemy potrzebować klasę Account Register. Poniżej przedstawię schemat prostej rejestracji nowego konta. Na początku będziemy potrzebować log z HttpAnalyzera, uruchamiamy program i klikamy na zieloną strzałkę. Następnie wchodzimy na stronę rejestracji i zakładamy nowe konto, strona zwróci nam różne zapytania i inne dane, zostaną zapisane przez HttpAnalyzera ;] Początek rejestracji : public override Account Register(String login, String haslo){ Nowy HttpClient, nasza pobieraczka stron, coś w stylu przeglądarki internetowej : this.httpclient = new HttpClient();
"6 "6 Link do rejestracji nowego konta : this.strpage = this.httpclient.getresponse("http://skrzynka.com/rejestruj"); Dodajemy wyjątek, jeśli powyższa strona się nie załaduje zwraca błąd w postaci komunikatu "Server not response" : if (this.strpage == "") throw new Exception(ExceptionClass.strSerwerNotResponse); Najważniejsze wyjątki (Przydatna klasa do rzucania wyjatków).: throw new Exception(ExceptionClass.strBadUserNameOrPassword); Spis wyjątków : ExceptionClass.strAccountCreatingLimitExceed; ExceptionClass.strAccountHasBlocked; ExceptionClass.strBadLoginChar; ExceptionClass.strBadPasswordChar; ExceptionClass.strBadUserNameOrPassword; ExceptionClass.strCannotCreated; ExceptionClass.strConnectionLost; ExceptionClass.strCreated; ExceptionClass.strDoesNotInterpretated; ExceptionClass.strExceedLimit; ExceptionClass.strLinkAlreadyUsed; ExceptionClass.strLogined; ExceptionClass.strLoginExiste; ExceptionClass.strLoginInError; ExceptionClass.strLonigIsTooShort; ExceptionClass.strPassError; ExceptionClass.strPasswordIsTooShort; ExceptionClass.strReturnedPageIsEmpty; ExceptionClass.strSendingError; ExceptionClass.strServerIsBusy; ExceptionClass.strSerwerNotResponse; ExceptionClass.strSessionLoginOver; ExceptionClass.strTokenError; ExceptionClass.strUnknownError; ExceptionClass.strUnknownSerwer;
"7 "7 Nie musimy korzystać z klasy ExceptionClass w YG, możemy dodać własny wyjątek, robimy to tak : (zamiast gotowego ExcePobieramy token (obrazek który należy przepisać) poniżej najprostsza postać tokenu, zwykły link, w którym nie zmieniają się żadne dane"ptionclass wpisujemy własny tekst) if (this.strpage.contains("ip Banned")) throw new Exception("Limit rejestracji nowych kont został przekroczony.); * Powyższy kod powinien zostać zapisany w jednej linii. Pobieramy token (obrazek który należy przepisać) poniżej najprostsza postać tokenu, zwykły link, w którym nie zmieniają się żadne dane"żadne dane" http://www.skrzynka.com/captcha/captcha.php Aby uzyskać link do tokenu, klikamy PPM na obrazek a następnie dajemy "Kopiuj adres obrazka" Gdy posiadamy już link, dajemy go do "String strtoken = "nasz_link" String strtoken = "http://www.skrzynka.com/captcha/captcha.php"; this.entertoken(new TokenEventArgs(this.httpClient.ImageResponse(strToken)));
"8 "8 Kolejnym krokiem jest przejście do zakładki POST w HttpAnalyzerze. Gdy klikniemy w link oznaczony jako post, w polu nr. 2 zobaczymy co jest wysyłane do serwera przez naszą przeglądarkę przy rejestracji konta. Są to dane w postaci loginu i hasła oraz innych... Dane które są wysyłane w POST do serwera : registration-variant 1 email name Imie nazwisko name-before-at wladimir889 domain-name 0 password haslo1234 one-more-password haslo1234 reserve-email altemail@host.com captcha dwg446 go???????????????????.??????????????????
"9 "9 Nie są one w najlepszej postaci, gdyż wiele istotnych danych nie jest wyświetlanych przechodzimy więc do zakładki "Data" po lewej stronie na dole. Zaznaczamy ciąg znaków z okienka, PPM i "Copy". Otrzymujemy ciąg : registration-variant=1&email=&name=imie+nazwisko&name-before-at=wladimir889&domainname=0&password=haslo1234&one-more-password=haslo1234&reserve-email=altemail %40host.com&captcha=dwg446&go=%D0%AF+%D1%81%D0%BE%D0%B3%D0%BB%D0%B0%D1%81%D0%B5%D0%BD+ %D1%81+%D0%BF%D1%80%D0%B0%D0%B2%D0%B8%D0%BB%D0%B0%D0%BC%D0%B8.+ %D0%97%D0%B0%D1%80%D0%B5%D0%B3%D0%B8%D1%81%D1%82%D1%80%D0%B8%D1%80%D0%BE %D0%B2%D0%B0%D1%82%D1%8C%D1%81%D1%8F
"10 "10 Potem postępujemy w następujący sposób : String request = "registration-variant=1&email=" + "&name=" + Los.imieEng() + " " + Los.nazwiskoEng() + "&name-before-at=" + login + "&domain-name=0&password=" + haslo + "&one-more-password=" + haslo + " "&reserve-email=" Los.adresEmail() + "&captcha=" + TokenText + "&go=%d0%af+%d1%81%d0%be%d0%b3%d0%bb%d0%b0%d1%81%d0%b5%d0%bd+%d1%81+%d0%bf %D1%80%D0%B0%D0%B2%D0%B8%D0%BB%D0%B0%D0%BC%D0%B8.+ %D0%97%D0%B0%D1%80%D0%B5%D0%B3%D0%B8%D1%81%D1%82%D1%80%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D1%82%D1%8C %D1%81%D1%8F"; Tworzymy request w którym za pomocą POST będziemy wysyłać dane z rejestracją tak jak w przypadku ręcznego wypełniania przez przeglądarkę. Następnie przedzielamy nasz ciąg znaków, dodając klasy odpowiedzialne za losowanie danych np. Los.adresEmail(). Klasy Los : Klasa przydatna podczas pisania kreatora ale nie tylko. Los.AdresEmail(); //Losuje Email w postaci "jankowalski88@wp.pl" Los.BigChar(); Los.Domeny(); //Losuje domenę w postaci "walla.com" Los.GetTimeInMilis(); Los.imieENG(); //Generuje Imię Eng Los.imiePL(); //Generuje Imię PL Los.imieRus(); Generuje Imię Rus Los.Login(); //Generuje Login Los.nazwiskoENG(); //Generuje Nazwisko Eng Los.nazwiskoPL(); //Generuje Nazwisko PL Los.rand.Next(9999); //Generuje lb Los.slownik(); // Losuje słowo ze słownika Los.ZipCode(); //Generuje kod w postaci "32444" Kolejnym krokiem jest określenie Thread.Speep np : Thread.Sleep(Los.rand.Next(6000, 10000));
"11 "11 ThreadSleep - uśpienia, opóźnienie itd, czyli czas w milisekundach jaki upływa zanim zostaną wysłane dane, w tym przypadku w post. Jest to bardzo ważne gdyż dane nie są wysyłane w 3s a cała rejestracja wygląda naturalniej, nie ma chyba człowieka co wypełniłby wszystkie kolumny w 3s. Wysyłamy powyższe dane, no właśnie tu za pomocą POST wysyłamy nasze dane, ważne jest aby w String... =, w naszym przypadku request, znajdował się identyczny ciąg znaków(nazwa itd). jaka jest poniżej po linku. Zamiast request możemy dać "dane" lub coś innego, jest to dowolne. Dla ułatwienia przy String request jak i na dole w linku został zaznaczony na zielono ;] this.strpage = this.httpclient.postresponse("http://skrzynka.com/rejestruj2", request); Aby kontrolować błędy podczas złego przepisania tokenu itp. należy zamieścić wyjątki - jest to napis bądź zdanie które zostaje wyświetlone np. podczas złego przepisania tokenu : if (this.strpage.contains("przepisany kod jest nieprawidłowy")) throw new Exception(ExceptionClass.strTokenError); if (this.strpage.contains("rejestracja udana")) throw new Exception(ExceptionClass.strCannotCreated); I teraz pora napisać skąd wziąć taki wyjątek, na stronie rejestracji w miejscu przeznaczony na przepisanie tokenu wpisujemy byle jakie daje i potwierdzamy rejestracje. Strona rzuci błędem w postaci np. "Przepisany kod jest nieprawidłowy" kopiujemy to co wyskoczy i dajemy do wyjątku. I teraz bardzo ważna rzecz, musimy rozróżnić pewną mało widoczną różnicę, mianowicie: if (this.strpage.contains ("Kod na obrazku jest inny")) throw new Exception(ExceptionClass.strTokenError); Samo if (this.strpage.contains oznacza jeśli strona zawiera napis... zwróć błąd if (this.strpage.contains("rejestracja udana")) throw new Exception(ExceptionClass.strCannotCreated);
"12 Gdy przed this.strpage znajduje się wykrzyknik wtedy to oznacza że jeśli na stronie nie ma napisu... to zwraca nam błąd. "12 Logout(); Czasami zdarza się ze po zakończeniu rejestracji jesteśmy automatycznie logowani, w tym przypadku należy się wylogować za pomocą klasy Logout(); return new Account(Host, login, haslo); } * Zwraca host, login i hasło do okienka w kreatorze kont po prawej stronie. 3. LOGOWANIE * Na przykładzie skrzynki gery.pl. public override void Login(string strlogin, string strpassword) { // Czyści ciasteczka this.httpclient.cookies = new CookieContainer(); // To wyłącza przekierowania this.httpclient.allowredir = false; //Otwiera stronę "https://poczta.gery.pl/" this.strpage = this.httpclient.getresponse("https://poczta.gery.pl/"); //Wysyła post this.strpage = this.httpclient.postresponse("https://poczta.gery.pl/", "_user="+strlogin+"&_pass="+strpassword+"&zaloguj=&_action=login"); // Jeśli strona zwróci nam "Błąd logowania" wtedy rzucamy wyjątek if (this.strpage.contains("błąd logowania")) { throw new Exception("BLAD"); } //Jeśli nie wyrzucił nam wyjątku znaczy leci dalej, otwiera stronę Przekierowania z "Location"(przejrzyjcie w HttpAnalizer) this.strpage = this.httpclient.getresponse("https://poczta.gery.pl/" + httpclient.myresponse.headers.get("location").replace(".", "")); //Jeśli strona zrwóci nam wyraz róźny od "Zalogowany" wtedy rzuci wyjątek "Nie zalogowany" if (this.strpage.contains("zalogowany")) { throw new Exception("Nie zalogowany"); } }
"13 Tyle po stronie kodu. Żeby do tego dojść trzeba włączyć HttpAnalizer na podsłuchu i otworzyć przeglądarkę internetową. Otwieramy stronę "https://poczta.gery.pl/" Wpisujemy dane : Login: jakislogin Hasło: jakishaslo Logujemy... Otwieramy HttpAnalizer i patrzymy jaki post rzucił. Widzimy na obrazku : "13 _user=jakislogin&_pass=jakishaslo&zaloguj=&_action=login Poniżej widzimy response Header i Location (Przekierowanie) które jest w kodzie :
"14 "14 4. WYLOGOWANIE Klasa Logout() jest niezbędna aby napisać nową skrzynkę w YG, odpowiada za wylogowanie z aktualnie używanego konta. Jest bardzo prosta, jedyne co nam będzie potrzebne to link wylogowujący, aby go zdobyć uruchamiamy HttpAnalyzera, klikamy na zieloną strzałkę w programie oraz w napis odpowiadający za wylogowanie z konta (np. używając Firefoxa). Po wykonaniu tej czynności przechodzimy do HttpAnalyzera i kopiujemy odpowiedni link np. http://skrzynka.com/logout Powyższy link wklejamy do uniwersalnej formy: "this.httpclient.getresponse("http://skrzynka.com/logout");"
"15 "15 Nasze GetResponse z linkiem odpowiada kliknięciu w "wyloguj" na stronie Cała klasa logout() wygląda następująco : public override void Logout() { if (this.httpclient = null) { this.httpclient.getresponse("http://skrzynka.com/logout"); this.httpclient.clean(); this.httpclient = null; } } 5. TOKENY Na wielu stronach są różne tokeny, dlatego postaramy się wytłumaczyć jak oprogramować najpopularniejsze z nich. http://www.skrzynka.pl/image.php Jest to najłatwiejsza wersja jaka może być, w linku nic się nie zmienia. Robimy tak: String Token = "http://www.skrzynka.pl/image.php"; EnterToken(new TokenEventArgs(httpClient.ImageResponse(Token))); Wersja trudniejsza http://skrzynka.pl/captcha/pm/vz/ap/jas_llxgoibx.gif W tym przypadku zmienia się środek, http://skrzynka.pl/captcha/ oraz.gif pozostaje bez zmian
"16 "16 Stosujemy wyrażenie regularne (.*?) które zastępuje ciąg znaków - losuje go. String captcha = Regex.Match(this.strPage, "http://szkrzynka.pl/captcha/(.*?).gif\"").groups[1].value; this.entertoken(new TokenEventArgs(SimpleCaptcha.Cut(this.httpClient.ImageResponse("http://skrzynka.pl/captcha/" + captcha + ".gif")))); Jeżeli nie mamy formatu na końcu to robimy tak: http://poczta1234/image/rwwgw4256gee63ewf String captcha = Regex.Match(this.strPage, "http://poczta1234/image/(.*?)\"").groups[1].value; this.entertoken(new TokenEventArgs(SimpleCaptcha.Cut(this.httpClient.ImageResponse("http://poczta1234/image/" + captcha)))); Tokeny od google Pomimo trudnego wyglądu bardzo łatwo się je robi, przy tradycyjnym tokenie klikamy na obrazek prawym przyciskiem myszy i dajemy kopiuj link... w tokenach recaptcha jest inaczej, jeżeli zrobimy tak jak przy tradycyjnym tokenie to otrzymamy długaśny link który do niczego nam się nie przyda np: http://www.google.com/recaptcha/api/image?c=03ahj_vuuofg2djk_vl1std_lxdkmx2eyu6w-4kig5ynitxg9d4abdd3pbicf0ffcokqjocunavfqrfjngnxdmetkxzmrq3wy6wwutzwc_efs9njcsnrmerf hf3ri_3pvlsgzeei7ljvcrmssnu6vff9evnymjm8quw Musimy zatem wyciągnąć ze strony stały ID obrazka, robimy to tak: PPM -> pokaż kod strony, i szukamy ;] Wygląda on tak: http://www.google.com/recaptcha/api/challenge?k=6lemjl4saaaaakrmm8qasbvjwyhzz5ejvmkklxeg
"17 "17 Jak go rozpoznać? Po pierwsze jest znacznie krótszy od pierwszego. Po drugie zawsze rozpoczyna się od: http://www.google.com/recaptcha/api/challenge?k= Jak już go znajdziemy to wklejamy go do uniwersalnej metody (pierwszy link) : String challenge = this.httpclient.getresponse("http://www.google.com/recaptcha/api/challenge?k=6lemjl4saaaaakrmm8qasbvjwyhzz5ejvmkklxeg"); Poleć znajomym String image = Regex.Match(challenge, "challenge\\s*:\\s*'([^']+)'").groups[1].value; itmap tokenimg = this.httpclient.imageresponse("http://www.google.com/recaptcha/api/image?c=" Poleć znajomym + image); EnterToken(new TokenEventArgs(tokenImg)); Niestety to jeszcze nie koniec, co prawda token się wyświetli ale najprawdopodobniej ten pierwszy hash o którym pisaliśmy będzie potrzebny. Za jego losowanie odpowiada: String image = Regex.Match(challenge, "challenge\\s*:\\s*'([^']+)'").groups[1].value; Ten kod dajemy np w: String request = "&code=" + TokenText + // to normalne "&recaptcha_challenge_field=" + image + // ten długi hash "&recaptcha_response_field="; 6. UPLOAD Upload jest niezbędny w działaniu P2M, dlatego w miarę jasno postaram się wyjaśnić jego działanie w Yg. Standardowo jak w poprzednich tutorialach będziemy potrzebować log z HttpAnalyzera. Włączamy program i klikamy w zieloną strzałkę.
"18 "18 Logujemy się na interesujący nas host i wysyłamy wiadomość wraz z załącznikiem na jakiś adres. Po wysłaniu wiadomości zatrzymujemy HttpAnalyzer czerwonym kwadratem obok zielonej strzałki i zapisujemy log aby w wyniku błędu nie stracić danych które uzyskaliśmy. Kolejnym krokiem jest stworzenie nowej funkcji odpowiedzialnej za upload: public override void UploadHTTP(Task zadanie, string[] to, string subject, string text, string file, string attname) { Aby móc wysyłać wiadomości potrzebujemy : String too = ""; foreach (String t in to) too += t + ", ";
"19 "19 Odpowiada to za dodawanie adresu w postaci : login@host.com Przechodzimy do naszego logu, który wykonaliśmy na początku i odszukujemy link który odpowiada za otwarcie okna z nową wiadomością: this.strpage = this.httpclient.getresponse("http://nowy.mail.skrzynka.com/"); Następnie szukamy linku oznaczonego jako POST, sprawdzamy jego zawartość klikając na "Post Data" Przechodzimy do zakładki "Data" po prawej stronie, ukaże nam się okno z danymi, zaznaczamy je i kopiujemy do notatnika.
"20 "20 Pomiędzy interesującymi nas danymi będą znajdować się śmieci:
"21 "21 Pomijamy je, przesuwając pasek na dół i kopiujemy podobnie wyglądające ciągi jak na początku. Gdy skopiujemy zawartość okna "Post Data" do notatnika musimy wykonać kilka czynności, dokładnie chodzi o wyciągnięcie odpowiednich danych. Będziemy potrzebować tylko te zaznaczona na niebiesko. Gdy dojdziemy do danych dotyczących załącznika pomijamy je, będą one potrzebne w późniejszym etapie. Wyglądają one mniej więcej tak: Content-Disposition: form-data; name="attachment"; filename="desert.jpg" Content-Type: image/jpeg Po wykonaniu powyższych czynności powinniśmy otrzymać kod w postaci: "FormCharset=utf-8&filled=1&selectedAddressBook=Contacts&To=" "&Cc=&Bcc=" "&Subject=" "&Priority=1&SendHTML=1&SaveSent=0" + "&Body=" &filled=1&send=1&startfilterbook=";
"22 "22 Dopisujemy dodawanie odbiorcy (too), nazwę tematu (subject) oraz tekst wiadomości (text) : String request = "FormCharset=utf-8&filled=1&selectedAddressBook=Contacts&To=" + too + "&Cc=&Bcc=" + "&Subject=" + subject + "&Priority=1&SendHTML=1&SaveSent=0" + "&Body=" + text + &filled=1&send=1&startfilterbook="; Tworzymy request wraz z załącznikiem korzystając z pominiętej linii: Content-Disposition: form-data; name="attachment"; filename="desert.jpg" Content-Type: image/jpeg Bierzemy z niej nazwę załącznika (zaznaczyłem ją na zielono), następnie dodajemy pomiędzy request, " a ", "", file, attname); this.strpage = this.httpclient.sendfile2(zadanie, "http://mail.skrzynka.com/compose.wssp", request, "attachment", "", file, attname); Na końcu dajemy wyjątek aby upewnić się że dana wiadomość została dostarczona. Strona wyświetla nam informację po wysłaniu wiadomości np : Twoja wiadomość została wysłana Dodajemy ją jako wyjątek: if (this.strpage.contains("twoja wiadomość została wysłana")) throw new Exception(ExceptionClass.strSendingError); }