Edge vs Chrome

Taka ciekawostka jak zachowuje się przeglądarka Microsoft Edge przy próbie pobrania instalatora Google Chrome.

Microsoft Edge za wszelką cenę próbuje zniechęcić do instalacji Chrome.

Nie byłoby w tym nic dziwnego, gdyby nie fakt, że instalator Chrome jest cyfrowo podpisany, jego sygnatury są jak na taki produkt ogólnie znane, a próba pobrania jakiegokolwiek innego instalatora cyfrowo podpisanego nie powoduje wyświetlania takiego komunikatu.

Brudne zagranie Microsoftu? Oceńcie sami.

Dlaczego Google wywalił tysiące pracowników?

Zwolnienia w Krzemowej Dolinie to coś co musiało nastąpić 🙂

Spójrzcie tylko kochane robaczki jak tam ciężko pracują! A ty jak tam robolu, piłeś dzisiaj matcha latte w pracy pomiędzy podziwianiem widoków z okna a spotkaniami z przyjaciółmi w swoim safe space?

Czy warto blokować boty wyszukiwarek?

Minęły dwa miesiące odkąd postanowiłem zablokować wszystkie mało znaczące boty wszelkiej maści dziwnych wyszukiwarek i spiderów sieciowych na swoich stronach.

Jakie rezultaty?

Zerowy spadek ruchu na stronach. Zerowy spadek w SERPach (nie blokuję Google). Znaczne odciążenie dla serwera. 3 x Wygrana.

Nie jestem szczególnie zaskoczony, bardziej zawiedziony, że mniej popularne wyszukiwarki nie mają najmniejszego znaczenia co do ruchu na stronach internetowych i nie warto ich botom pozwalać na niepotrzebne zjadanie serwerowych zasobów.

XRumer 12.0.11 i nowa reCAPTCHA od Google pokonana

Nowy XRumer, czyli oprogramowanie do masowego spamowania zyskało obsługę nowego mechanizmu reCAPTCHA od Google.

reCAPTCHA

Dzisiejszy komunikat:

New revolutionary technology make of new Google ReCaptcha defeated! Average time of recognition: 20 MILLIseconds! (0,02 sec).

Also, the program was trained to new popular types of graphical captcha, included animated GIF-captchas and Flash-captchas.

Added new Wizard to set up Project+Options+Scheduler just with one click: useful feature 😉

Mass-PM system was significantly updated. Possibility to send millions of personal messages all over the world is becoming a reality.

Significantly increased the success rate and improved work with several engines, so now software become more powerful (read more info on our tech.support forum).

Adjusted the processing of CloudFlare (applied a new mechanism of decoding of ReCaptcha)

New databases with more than 300,000 unique resources, so hurry up to use it!

Update can be downloaded from your client area on our site.

Z ciekawostek powiem, że BotmasterLabs często organizuje konkursy o spore pieniądze, których celem jest poprawienie działania mechanizmów rozpoznawania kodów CAPTCHA w Xrumerze. Ostatni konkurs odbył się we wrześniu 2014 roku i nagrodą było 15000 USD.

Jak widać cyberprzestępcy są szybko krok do przodu nawet przed takim gigantem jak Google. Zastanawiający jest fakt, pseudo-firma spamerska jest w stanie więcej zapłacić niż Google swoim inżynierom lub zorganizować konkurs na stworzenie lepszych mechanizmów.

Technologiczna bieda kompilatora Go

Lubię babrać się w low levelu, to zarówno moja pasja jak i praca. Jestem w trakcie testowania nowego exe protectora i jak to zwykle bywa – testuje nim co popadnie, wliczając wszelkie nietypowe pliki w formacie PE, w tym pliki z różnych kompilatorów i środowisk programistycznych jak np. DMD, Lazarus / FPC, PureBasic, a nawet takie antyki jak WATCOM.

Różne kompilatory stosują całą mase magicznych zabiegów, aby czasami nieświadomie uniemożliwić zabezpieczenie wygenerowanego pliku PE EXE, a ja staram się to ładnie obsłużyć, ominąć, hookować etc.

Dzisiaj przysiadłem sobie do kompilatora języka wprost od Google, czyli – Go.

…i zdębiałem. Ściągnąłem paczkę v1.3.1 dla Windows w wersji 32 bitowej.

O ile protector poradził sobie bez zająknięcia z testowym zabezpieczeniem pliku kompilatora – go.exe, o tyle nie byłbym sobą jeśli bym nie zajrzał do środka, jak strukturalnie zbudowany jest plik z Go (biorąc pod uwagę, że kompilator Go zbudowany jest ze źródeł w C oraz samym języku Go).

A w środku szalone lata 90 :), spójrzmy na to razem:

1. Mania używania CLD

CLD to instrukcja procesora ustawiająca flagę kierunku wykonywania operacji takich jak rep stosb, rep movsd, scasb, jej zresetowanie powoduje, że operacje te wykonują się bajt po bajcie w kolejności rosnącej, jej ustawienie powoduje, że operacje te wykonują się odwrotnie (czyli od końca do przodu).

Problem w tym, że na systemach Windows ta flaga jest domyślnie już wyzerowana, a funkcje WinApi nigdy jej nie ustawiają, rzadkością są w ogóle przypadki, że kiedykolwiek jest ona ustawiana instrukcją STD, chyba jedynie w jakichś egzotycznych przykładach napisanych w assemblerze.

W binarce go.exe znajdziemy tego całą masę:

.text:00473CF8                 call    runtime_emptyfunc
.text:00473CFD                 cld
.text:00473CFE                 call    runtime_check

W 1 bloku kodu (a co, kto bogatemu zabroni):

.text:004BCB1E                 lea     esi, off_742838
.text:004BCB24                 lea     edi, [esp+88h+var_80]
.text:004BCB28                 cld
.text:004BCB29                 movsd
.text:004BCB2A                 movsd
.text:004BCB2B                 lea     esi, off_740DF8
.text:004BCB31                 lea     edi, [esp+88h+var_78]
.text:004BCB35                 cld
.text:004BCB36                 movsd
.text:004BCB37                 movsd
.text:004BCB38                 mov     [esp+88h+var_70], 0FFFFFFFFh

Jeszcze tutaj:

.text:00650751                 lea     esi, [esp+68h+var_44]
.text:00650755                 lea     edi, [esp+68h+var_24]
.text:00650759                 cld
.text:0065075A                 call    sub_475CA0

I w całej masie kodu wszędzie CLD. Co ciekawe nie znalazłem w binarce ani jednej instrukcji STD, która sprawiałaby, że trzeba użyć CLD 😉

2. Undefined behaviour

W assemblerze znajdziemy instrukcje, których znaczenia nie zna nawet taki wymiatacz assemblera jak Rysio z Klanu. Wśród nich znajdziemy tajemniczą instrukcję UD2, lata temu stosowałem ją w metodach antydebug ze względu na to, że deasemblery w popularnych debuggerach nie wiedziały co z nią robić. Obecnie jest udokumentowana jako celowo nieprawidłowa instrukcja do testowania (sprytnie).

Jej zastosowanie w kodzie generowanym w nowoczesnych kompilatorach praktycznie nie istnieje. Na co komuś instrukcja, która niczego nie robi (oprócz linuxiarzy)? W kodzie kompilatora Go znalazła zastosowanie:

.text:004BC84B loc_4BC84B:                             ; CODE XREF: path_filepath_volumeNameLen+1BAj
.text:004BC84B                 call    runtime_panicindex
.text:004BC850                 ud2
.text:004BC852 ; ---------------------------------------------------------------------------
.text:004BC852
.text:004BC852 loc_4BC852:                             ; CODE XREF: path_filepath_volumeNameLen+1C8j
.text:004BC852                                         ; path_filepath_volumeNameLen+1CFj
.text:004BC852                 mov     ebp, 1
.text:004BC857                 jmp     short loc_4BC833
.text:004BC859 ; ---------------------------------------------------------------------------
.text:004BC859
.text:004BC859 loc_4BC859:                             ; CODE XREF: path_filepath_volumeNameLen+198j
.text:004BC859                 call    runtime_panicindex
.text:004BC85E                 ud2
.text:004BC860 ; ---------------------------------------------------------------------------
.text:004BC860
.text:004BC860 loc_4BC860:                             ; CODE XREF: path_filepath_volumeNameLen+184j
.text:004BC860                                         ; path_filepath_volumeNameLen+18Bj
.text:004BC860                 mov     ebp, 1
.text:004BC865                 jmp     short loc_4BC7EF
.text:004BC867 ; ---------------------------------------------------------------------------
.text:004BC867
.text:004BC867 loc_4BC867:                             ; CODE XREF: path_filepath_volumeNameLen+172j
.text:004BC867                 call    runtime_panicindex
.text:004BC86C                 ud2

Jest ona tu zastosowana jako bariera, upewniająca, że po runtime_panicindex nic nie zostanie wykonane. Tak dla picu i marnotrastwa miejsca. To tak jakby po ExitProcess() dać dla bajery int 3.

3. Optymalizacyjne potworki

Są takie instrukcje, których manuale zarówno Intela jak i AMD rekomendują omijać szerokim łukiem. Dlaczego? Bo to archaiczne twory z początków procesorów 386, które przetrwały na liście instrukcji, jednak nikt ich już od tamtych czasów nie optymalizował w silikonie i nikt ich nie używa, oprócz paru szalonych programistów assemblera, którzy optymalizują kod pod względem rozmiaru.

Jedną z takich instrukcji jest xchg, która wymienia zawartość 2 rejestrów, od czasów MS-DOS nie widziałem, żeby jakikolwiek kompilator generował tą instrukcję w kodzie (oprócz ręcznych wstawek w assemblerze). A tutaj mamy tego całą masę:

.text:004BC7C4                 xchg    eax, ebp
.text:004BC7C5                 cmp     al, 0
.text:004BC7C8                 xchg    eax, ebp
.text:004BC7C9                 jz      loc_4BC86E
.text:004BC7CF                 inc     eax
.text:004BC7D0                 cmp     eax, ecx
.text:004BC7D2                 jnb     loc_4BC867
.text:004BC7D8                 lea     ebp, [edx+eax]
.text:004BC7DB                 movzx   ebp, byte ptr [ebp+0]
.text:004BC7DF                 xchg    eax, ebp
.text:004BC7E0                 cmp     al, 5Ch
.text:004BC7E3                 xchg    eax, ebp
.text:004BC7E4                 jz      short loc_4BC860
.text:004BC7E6                 xchg    eax, ebp
.text:004BC7E7                 cmp     al, 2Fh
.text:004BC7EA                 xchg    eax, ebp
.text:004BC7EB                 jz      short loc_4BC860
.text:004BC7ED                 xor     ebp, ebp

Na pohybel  manualom :P, już nawet nie mówię, że ten kod wygląda tak biednie, że mam ochotę dać darowiznę, nawet niewprawiony programista assemblera lepiej by to napisał.

Kolejny:

.text:00473F19                 mov     eax, offset runtime_call16
.text:00473F1E                 jmp     eax

Podpowiem tym razem: jmp runtime_call16 i jesteście 2 bajty do przodu, niczego nie tracąc, a wręcz zyskując, jmp w tym wypadku to relatywny skok, więc wynikowy plik PE EXE będzie jeszcze mniejszy o rozmiar relokacji używany w instrukcji mov eax,adres_w_pamieci.

I znowu:

.text:0066A88E                 and     ebx, 7
.text:0066A891                 cmp     ebx, 0
.text:0066A894                 jz      short loc_66A89F

Każdy lamer zaczynający programować w assemblerze później czy prędzej dowie się, że instrukcje takie jak and, or, xor ustawiają również flagi w zależności od wyniku wykonanej operacji, nie trzeba dodatkowo stosować porównania do sprawdzenia flagi.

Go lubi nadmiarowy kod:

.text:005FEE6C                 xor     ebx, ebx
.text:005FEE6E                 cmp     eax, ebx
.text:005FEE70                 jz      short loc_5FEEA4

Komentarz? 3 instrukcje do sprawdzenia czy rejestr EAX zawiera wartość 0. Na całym świecie kompilatorowym załatwiają to 2 instrukcje test eax,eax lub cmp eax,0 + skok.

4. Na pohybel Windowsowi

Nikt o zdrowych zmysłach nie korzysta w produkcyjnym kodzie ze struktur takich jak np. PEB czy TEB, gdyż wskutek ewolucji systemów operacyjnych, ich pola zawsze mogą się zmienić. Nikt oprócz kompilatora go.exe, który radośnie wykorzystuje go do śledzenia stosu i w razie potrzeby zwiększania jego rozmiaru:

.text:00473E10                 mov     ecx, large fs:14h
.text:00473E17                 mov     ebx, [ecx+4]
.text:00473E1D                 mov     esi, [ebx]

Kto o zdrowych zmysłach i wbrew dokumentacji, która wyraźnie zaznacza, że struktury te mogą się zmienić w kolejnych wersjach systemu operacyjnego decyduje się na korzystanie z nich? Chyba ktoś, kto nigdy swojego oprogramowania nie testował na 2 różnych wersjach systemu Windows, albo nie zakłada, że będzie on musiał działać na innym OS.

5. Mamy swój standard

W świecie Windows istnieje określony sposób wywoływania funkcji WinApi – określany mianem stdcall, który zakłada, że kolejne parametry są wrzucane na stos i następuje wywołanie zadanej funkcji. Seria instrukcji push zakończona instrukcją call. Proste? Za proste! Skomplikujmy to. Oto jak wygląda wywoływanie funkcji WinApi w go.exe:

.text:00458C33                 mov     eax, SetConsoleCtrlHandler
.text:00458C39                 mov     [esp+14h+var_14], eax
.text:00458C3C                 mov     eax, 2
.text:00458C41                 mov     [esp+14h+var_10], eax
.text:00458C45                 mov     eax, offset runtime_ctrlhandler
.text:00458C4A                 mov     [esp+14h+var_C], eax
.text:00458C4E                 mov     eax, 1
.text:00458C53                 mov     [esp+14h+var_8], eax
.text:00458C57                 call    runtime_stdcall

Czyli istnieje sobie wrapper o sweetaśnej nazwie runtime_stdcall(), któremu przekazywana jest funkcja jako wskaźnik, parametry, a wrapper sam wywołuje instrukcję call. Po co? Kto bogatemu zabroni!

Wnioski

Pierwszy jest taki, że jestem cholernie zawiedziony jakością kodu Go, jak widać można mieć górę pieniędzy, a i tak być technologicznie zacofanym do epoki kamienia łupanego.

Wiem, że w dobie nowych procesorów Intel Core i7 mało kto zwraca uwagę na takie detale, jednak nie wiem czy chciałbym aby moje oprogramowanie i algorytmy były kompilowane do takiej formy jaką obecnie oferuje najnowszy kompilator Go. To się po prostu nie dodaje jak mówi Mariusz Max Kolonko…

Na koniec jeszcze dump z programu Hello World w Go:

package main

import "fmt"

func main() {
	fmt.Println("Hello, 世界")
}
.text:00401000 main_main       proc near               ; CODE XREF: main_main+1Aj
.text:00401000                                         ; runtime_main+119p
.text:00401000                                         ; DATA XREF: runtime_sighandler+42o
.text:00401000                                         ; .text:off_4CFD0Co
.text:00401000
.text:00401000 var_40          = dword ptr -40h
.text:00401000 var_3C          = dword ptr -3Ch
.text:00401000 var_38          = dword ptr -38h
.text:00401000 var_1C          = dword ptr -1Ch
.text:00401000 var_18          = dword ptr -18h
.text:00401000 var_14          = byte ptr -14h
.text:00401000 var_C           = dword ptr -0Ch
.text:00401000 var_8           = dword ptr -8
.text:00401000 var_4           = dword ptr -4
.text:00401000
.text:00401000                 mov     ecx, large fs:14h
.text:00401007                 mov     ecx, [ecx+0]
.text:0040100D                 cmp     esp, [ecx]
.text:0040100F                 ja      short loc_40101C
.text:00401011                 xor     edi, edi
.text:00401013                 xor     eax, eax
.text:00401015                 call    runtime_morestack_noctxt
.text:0040101A                 jmp     short main_main
.text:0040101C ; ---------------------------------------------------------------------------
.text:0040101C
.text:0040101C loc_40101C:                             ; CODE XREF: main_main+Fj
.text:0040101C                 sub     esp, 40h
.text:0040101F                 lea     ebx, off_4B1260
.text:00401025                 mov     ebp, [ebx]
.text:00401027                 mov     [esp+40h+var_1C], ebp
.text:0040102B                 mov     ebp, [ebx+4]
.text:0040102E                 mov     [esp+40h+var_18], ebp
.text:00401032                 lea     edi, [esp+40h+var_14]
.text:00401036                 xor     eax, eax
.text:00401038                 stosd
.text:00401039                 stosd
.text:0040103A                 lea     ebx, [esp+40h+var_14]
.text:0040103E                 cmp     ebx, 0
.text:00401041                 jz      short loc_401096
.text:00401043
.text:00401043 loc_401043:                             ; CODE XREF: main_main+98j
.text:00401043                 mov     [esp+40h+var_C], ebx
.text:00401047                 mov     [esp+40h+var_8], 1
.text:0040104F                 mov     [esp+40h+var_4], 1
.text:00401057                 mov     [esp+40h+var_40], offset dword_48CEE0
.text:0040105E                 lea     ebx, [esp+40h+var_1C]
.text:00401062                 mov     [esp+40h+var_3C], ebx
.text:00401066                 call    runtime_convT2E
.text:0040106B                 mov     edx, [esp+40h+var_C]
.text:0040106F                 lea     ebx, [esp+40h+var_38]
.text:00401073                 mov     esi, ebx
.text:00401075                 mov     edi, edx
.text:00401077                 cld
.text:00401078                 movsd
.text:00401079                 movsd
.text:0040107A                 mov     [esp+40h+var_40], edx
.text:0040107D                 mov     ebx, [esp+40h+var_8]
.text:00401081                 mov     [esp+40h+var_3C], ebx
.text:00401085                 mov     ebx, [esp+40h+var_4]
.text:00401089                 mov     [esp+40h+var_38], ebx
.text:0040108D                 call    fmt_Println
.text:00401092                 add     esp, 40h
.text:00401095                 retn
.text:00401096 ; ---------------------------------------------------------------------------
.text:00401096
.text:00401096 loc_401096:                             ; CODE XREF: main_main+41j
.text:00401096                 mov     [ebx], eax
.text:00401098                 jmp     short loc_401043
.text:00401098 main_main       endp

Jeśli i wy doceniacie piękno assemblera i gardzicie lipnym kodem wpiszcie w komentarzach waszą wersję tej funkcji, najlepszy wpis czeka nagrodapierwszy plakat formatu PE (bo już nie mam go gdzie powiesić). Nie spodziewam się rewelacji z waszej strony, ale kto wie 😉