# ============================================================================= # MCGRY.PL - OFICJALNY SKRYPT SPRAWDZANIA (screenshare) # Zrodlo: https://sprawdzanie.mcgry.pl # ----------------------------------------------------------------------------- # UWAGA: caly plik jest celowo bez polskich ogonkow i bez zadnej obfuskacji, # zebys mogl przeczytac kazda linijke i miec pewnosc, co sie dzieje. # ----------------------------------------------------------------------------- # CO TEN SKRYPT ROBI: # - odczytuje pamiec uruchomionego procesu Minecrafta (javaw.exe / java.exe) # - szuka w niej sygnatur znanych cheatow (jawna lista nizej) # - wypisuje wynik na ekran wraz z adresem, pod ktorym znalazl trafienie # # CZEGO TEN SKRYPT NIE ROBI (sprawdz sam - Ctrl+F w tym pliku): # - NIE laczy sie z internetem (brak: Invoke-WebRequest, Invoke-RestMethod, # Net.WebClient, DownloadString, curl, wget, Start-BitsTransfer, HttpClient) # - NIE czyta plikow z kontami/haslami/sesjami (brak: launcher_accounts.json, # launcher_profiles.json, usercache, .minecraft, AppData, Credentials) # - NIE uruchamia innych programow (brak: Start-Process, cmd.exe) # - NIE zapisuje, nie modyfikuje i nie usuwa zadnych plikow # - NIE prosi o haslo, kod z e-maila ani o zadne dane # # UCZCIWA UWAGA O "iex": # Sam skrypt nie wywoluje iex ani Invoke-Expression - nie znajdziesz ich # ponizej poza tym komentarzem. Ale jesli wkleiles wariant jednolinijkowy # ("cala komenda" ze strony), to zaczyna sie on od: # iex (( ...linie tego skryptu... ) -join "`n") # Ten iex skleja z powrotem i uruchamia DOKLADNIE ten tekst, ktory masz # przed soba - nie pobiera niczego z sieci i nie siega po zaden inny kod. # Nie chcemy udawac, ze go tam nie ma: opis ma sie zgadzac z kodem. # # Skrypt otwiera proces gry z minimalnymi uprawnieniami: TYLKO ODCZYT pamieci # (PROCESS_VM_READ | PROCESS_QUERY_INFORMATION). Nic nie zapisuje do gry. # ============================================================================= $ErrorActionPreference = 'Stop' $SCRIPT_VERSION = '2.2.0' $SCRIPT_BRAND = 'MCGRY.PL' $SCRIPT_SOURCE = 'https://sprawdzanie.mcgry.pl' $SCRIPT_TOKEN = 'TK2YGJ-6F1D9B3822B2' # jednorazowy token wydany przez serwer # ============================================================================= # KROK 0 - KONTROLA UCZCIWOSCI SESJI # Sprawdzamy, czy ktos nie podmienil w tej sesji PowerShell komend, ktorych # uzywamy (klasyczny sposob oszukania screenshare'a). Odwolujemy sie do # silnika PowerShell bezposrednio, bo samo Get-Command tez da sie podmienic. # ============================================================================= $__integrity = @() if ($ExecutionContext.SessionState.LanguageMode -ne 'FullLanguage') { $__integrity += "Tryb jezyka PowerShell: $($ExecutionContext.SessionState.LanguageMode) (oczekiwano FullLanguage)" } $__expected = @{ 'Get-Process' = 'Microsoft.PowerShell.Management' 'Add-Type' = 'Microsoft.PowerShell.Utility' 'Write-Host' = 'Microsoft.PowerShell.Utility' 'Get-Date' = 'Microsoft.PowerShell.Utility' 'Sort-Object' = 'Microsoft.PowerShell.Utility' 'Measure-Object' = 'Microsoft.PowerShell.Utility' 'ForEach-Object' = 'Microsoft.PowerShell.Core' 'Get-History' = 'Microsoft.PowerShell.Core' } foreach ($__n in $__expected.Keys) { $__c = $ExecutionContext.InvokeCommand.GetCommand($__n, [System.Management.Automation.CommandTypes]::All) if ($null -eq $__c) { $__integrity += "Brak komendy $__n" } elseif ($__c.CommandType -ne [System.Management.Automation.CommandTypes]::Cmdlet -or $__c.ModuleName -ne $__expected[$__n]) { $__integrity += "Komenda $__n zostala podmieniona w tej sesji ($($__c.CommandType))" } } # Klasa skanera dostaje losowa nazwe przy KAZDYM pobraniu skryptu z serwera. # Jesli typ o tej nazwie juz istnieje, ktos probowal go podstawic wczesniej. if (([System.Management.Automation.PSTypeName]'KFB8ED4F88DB9').Type) { $__integrity += 'Typ KFB8ED4F88DB9 juz istnieje w tej sesji (proba podstawienia falszywego skanera)' } # ============================================================================= # Rysowanie interfejsu # ============================================================================= $Unicode = $true try { [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 } catch { $Unicode = $false } try { $Host.UI.RawUI.WindowTitle = "McGry - Sprawdzanie v$SCRIPT_VERSION" } catch { } if ($Unicode) { $G = @{ DTL = [char]0x2554; DTR = [char]0x2557; DBL = [char]0x255A; DBR = [char]0x255D DH = [char]0x2550; DV = [char]0x2551 TL = [char]0x250C; TR = [char]0x2510; BL = [char]0x2514; BR = [char]0x2518 H = [char]0x2500; V = [char]0x2502; ML = [char]0x251C; MR = [char]0x2524 FULL= [char]0x2588; HALF= [char]0x2591; DOT = [char]0x00B7; ELL = [char]0x2026 OK = [char]0x2714; BAD = [char]0x2718; WARN= [char]0x0021 } } else { $G = @{ DTL='+'; DTR='+'; DBL='+'; DBR='+'; DH='='; DV='|' TL='+'; TR='+'; BL='+'; BR='+'; H='-'; V='|'; ML='+'; MR='+' FULL='#'; HALF='-'; DOT='.'; ELL='~'; OK='+'; BAD='x'; WARN='!' } } $W = 78 # szerokosc ramki $IN = $W - 2 # szerokosc wnetrza ramki $PAD = ' ' # wciecie od lewej krawedzi konsoli function Fit([string]$Text, [int]$Len) { if ($null -eq $Text) { $Text = '' } if ($Text.Length -le $Len) { return $Text.PadRight($Len) } return $Text.Substring(0, [Math]::Max(1, $Len - 1)) + $G.ELL } function Box-Top([string]$Title, [string]$Color = 'DarkGray', [switch]$Double) { $tl = $(if ($Double) { $G.DTL } else { $G.TL }) $tr = $(if ($Double) { $G.DTR } else { $G.TR }) $h = $(if ($Double) { $G.DH } else { $G.H }) if ($Title) { $label = " $Title " $rest = $IN - 1 - $label.Length if ($rest -lt 0) { $rest = 0 } Write-Host ($PAD + $tl + [string]$h) -ForegroundColor $Color -NoNewline Write-Host $label -ForegroundColor White -NoNewline Write-Host (([string]$h * $rest) + $tr) -ForegroundColor $Color } else { Write-Host ($PAD + $tl + ([string]$h * $IN) + $tr) -ForegroundColor $Color } } function Box-Bottom([string]$Color = 'DarkGray', [switch]$Double) { $bl = $(if ($Double) { $G.DBL } else { $G.BL }) $br = $(if ($Double) { $G.DBR } else { $G.BR }) $h = $(if ($Double) { $G.DH } else { $G.H }) Write-Host ($PAD + $bl + ([string]$h * $IN) + $br) -ForegroundColor $Color } function Box-Sep([string]$Color = 'DarkGray') { Write-Host ($PAD + $G.ML + ([string]$G.H * $IN) + $G.MR) -ForegroundColor $Color } # Segmenty: @( @{T='tekst'; C='Kolor'}, ... ) - reszta linii dopelniana spacjami function Box-Row([object[]]$Segments, [string]$Color = 'DarkGray', [switch]$Double) { $v = $(if ($Double) { $G.DV } else { $G.V }) $len = 0 foreach ($s in $Segments) { $len += $s.T.Length } Write-Host ($PAD + $v) -ForegroundColor $Color -NoNewline foreach ($s in $Segments) { $c = $s.C; if (-not $c) { $c = 'Gray' } Write-Host $s.T -ForegroundColor $c -NoNewline } $fill = $IN - $len if ($fill -lt 0) { $fill = 0 } Write-Host ((' ' * $fill) + $v) -ForegroundColor $Color } function Box-Empty([string]$Color = 'DarkGray', [switch]$Double) { Box-Row @(@{ T = ''; C = 'Gray' }) $Color -Double:$Double } function Box-Field([string]$Label, [string]$Value, [string]$ValueColor = 'White') { Box-Row @( @{ T = ' ' + (Fit $Label 14); C = 'DarkGray' }, @{ T = $Value; C = $ValueColor } ) } function Write-Banner { # Dopelnienie liczone z faktycznych dlugosci segmentow, a nie wpisane na # sztywno - nazwa serwera jest podstawiana przy pobraniu i moze miec # dowolna dlugosc. $segBrand = ' ' + $SCRIPT_BRAND $segDot = ' ' + [string]$G.DOT + ' ' $segTitle = 'OFICJALNE SPRAWDZANIE KLIENTA' $segVer = 'v' + $SCRIPT_VERSION # UWAGA: nie nazywac tej zmiennej $pad - PowerShell ignoruje wielkosc liter, # wiec nadpisalaby globalne $PAD (wciecie ramki), a funkcje wywolywane nizej # dziedzicza zakres wywolujacego i dostalyby liczbe zamiast spacji. $gap = $IN - $segBrand.Length - $segDot.Length - $segTitle.Length - $segVer.Length - 1 if ($gap -lt 1) { $gap = 1 } Write-Host '' Box-Top '' 'DarkCyan' -Double Box-Row @( @{ T = $segBrand; C = 'Cyan' }, @{ T = $segDot; C = 'DarkCyan' }, @{ T = $segTitle; C = 'White' }, @{ T = ((' ' * $gap) + $segVer); C = 'DarkCyan' } ) 'DarkCyan' -Double Box-Bottom 'DarkCyan' -Double } function Write-Verdict([string]$Title, [string]$Sub, [string]$Bg, [string]$Fg) { $line = ' ' * $W Write-Host '' Write-Host ($PAD + $line) -BackgroundColor $Bg -ForegroundColor $Fg Write-VerdictLine $Title $Bg $Fg if ($Sub) { Write-VerdictLine $Sub $Bg $Fg } Write-Host ($PAD + $line) -BackgroundColor $Bg -ForegroundColor $Fg Write-Host '' } # Wysrodkowanie z DOKLADNIE rownym odstepem po obu stronach. Gdy margines # wychodzi nieparzysty, tekst dostaje jedna spacje - inaczej blok przechyla # sie o jeden znak i odstepy wygladaja na rozjechane. function Write-VerdictLine([string]$Text, [string]$Bg, [string]$Fg) { $t = $Text if ($t.Length -gt $W) { $t = $t.Substring(0, $W) } if ((($W - $t.Length) % 2) -eq 1) { $t = $t + ' ' } $side = ($W - $t.Length) / 2 Write-Host ($PAD + (' ' * $side) + $t + (' ' * ($W - $side - $t.Length))) -BackgroundColor $Bg -ForegroundColor $Fg } function Show-Progress([int]$Percent, [string]$Label, [int]$Mb, [double]$Seconds) { $barW = 30 $fill = [int]($barW * $Percent / 100) if ($fill -gt $barW) { $fill = $barW } if ($fill -lt 0) { $fill = 0 } $bar = ([string]$G.FULL * $fill) + ([string]$G.HALF * ($barW - $fill)) $speed = 0 if ($Seconds -gt 0.2) { $speed = [int]($Mb / $Seconds) } Write-Host ("`r" + $PAD + ' ') -NoNewline Write-Host $bar -ForegroundColor Cyan -NoNewline Write-Host (" {0,3}% " -f $Percent) -ForegroundColor White -NoNewline Write-Host ("{0,-22} {1,6} MB {2,5} MB/s " -f $Label, $Mb, $speed) -ForegroundColor DarkGray -NoNewline } function Write-Footer([string]$SessionId, [datetime]$Started) { Box-Top 'BEZPIECZENSTWO' 'DarkGray' Box-Row @(@{ T = ' Dla bezpieczenstwa mozesz skopiowac ze strony CALA komende -'; C = 'White' }) Box-Row @(@{ T = ' caly skrypt w jednej linii. Wtedy nic nie jest pobierane'; C = 'White' }) Box-Row @(@{ T = ' z sieci, a przed wklejeniem widzisz dokladnie to, co uruchamiasz.'; C = 'White' }) Box-Row @(@{ T = (' ' + $SCRIPT_SOURCE); C = 'Cyan' }) Box-Empty Box-Row @(@{ T = ' Jesli ktokolwiek kaze Ci wpisac INNA komende - odmow i zglos to.'; C = 'Gray' }) Box-Row @(@{ T = ' Administracja NIGDY nie prosi o haslo, kod z e-maila ani plik'; C = 'Gray' }) Box-Row @(@{ T = ' z konta. Adres wpisuj recznie, nie z prywatnej wiadomosci.'; C = 'Gray' }) Box-Sep Box-Row @( @{ T = ' Kod sesji '; C = 'DarkGray' }, @{ T = (Fit $SessionId 10); C = 'Yellow' }, @{ T = 'Token '; C = 'DarkGray' }, @{ T = (Fit $SCRIPT_TOKEN 22); C = 'Yellow' }, @{ T = $Started.ToString('yyyy-MM-dd HH:mm'); C = 'DarkGray' } ) Box-Row @(@{ T = (' Weryfikacja tokenu: ' + $SCRIPT_SOURCE + '/weryfikacja'); C = 'DarkGray' }) Box-Bottom Write-Host '' } # ============================================================================= # SYGNATURY - jawna lista szukanych ciagow znakow ("kodow") # Level: H = pewne wykrycie, L = poszlaka (krotki ciag, mozliwy falszywy alarm) # ============================================================================= $SIGNATURES = @( @{ Cat = 'KLIENCI CHEATOW'; Name = 'Nursultan'; Level = 'H'; Pattern = 'nursultan' }, @{ Cat = 'KLIENCI CHEATOW'; Name = 'Ventura Client'; Level = 'H'; Pattern = 'eu/venturaclient/misc/misc/GameAccessor.classPK' }, @{ Cat = 'KLIENCI CHEATOW'; Name = 'Azure (peleryna)'; Level = 'H'; Pattern = '/assets/anamvmnt/textures/capes/custom/azure.png' }, # Korzenie pakietow klientow. Kazdy z nich jest podciagiem setek wariantow # z surowych list (np. 'su/catlean' zawiera sie w 2403 wzorcach Catleana), # wiec wykrywa dokladnie to samo przy 2403 razy mniejszym koszcie skanu. # Wszystkie zweryfikowane na czystym kliencie: zero trafien. @{ Cat = 'KLIENCI CHEATOW'; Name = 'Catlean'; Level = 'H'; Pattern = 'su/catlean' }, @{ Cat = 'KLIENCI CHEATOW'; Name = 'Meteor Client'; Level = 'H'; Pattern = 'meteordevelopment/meteorclient' }, @{ Cat = 'KLIENCI CHEATOW'; Name = 'Vanadium'; Level = 'H'; Pattern = 'nl/vanadium' }, @{ Cat = 'KLIENCI CHEATOW'; Name = 'Vanadium (JNI)'; Level = 'H'; Pattern = 'nl_vanadium' }, @{ Cat = 'KLIENCI CHEATOW'; Name = 'Vanadium (vanahui)'; Level = 'H'; Pattern = 'vanahui' }, @{ Cat = 'KLIENCI CHEATOW'; Name = 'Ventura (pakiet)'; Level = 'H'; Pattern = 'venturaclient' }, @{ Cat = 'KLIENCI CHEATOW'; Name = 'Ventura (candyman)'; Level = 'H'; Pattern = 'candyman/' }, @{ Cat = 'KLIENCI CHEATOW'; Name = 'ThunderHack'; Level = 'H'; Pattern = 'ThunderHack' }, @{ Cat = 'KLIENCI CHEATOW'; Name = 'Aristois'; Level = 'H'; Pattern = 'aristois' }, @{ Cat = 'KLIENCI CHEATOW'; Name = 'BleachHack'; Level = 'H'; Pattern = 'BleachHack' }, @{ Cat = 'KLIENCI CHEATOW'; Name = 'Wurst'; Level = 'H'; Pattern = 'Wurst' }, # Cheat nazwany tak samo jak anticheat Grim (celowo, dla zmylki). # Samo slowo "grim" jest bezuzyteczne jako sygnatura - to zwykle slowo # i trafia w czystym kliencie. Uzywamy korzenia jego pakietu. @{ Cat = 'KLIENCI CHEATOW'; Name = 'Grim (cheat)'; Level = 'H'; Pattern = 'sixfive/' }, # Nazwy projektow wydobyte z surowych list (assets//, handler$..$$, # dev//, :textures/) i zweryfikowane na czystym kliencie. @{ Cat = 'KLIENCI CHEATOW'; Name = 'Nerith'; Level = 'H'; Pattern = 'nerith' }, # 'jnic' bez kotwicy ma 4 znaki - taki ciag malych liter trafia sie w kazdym # dluzszym tekscie base64 i w danych binarnych. Uzywamy form z separatorem. @{ Cat = 'KLIENCI CHEATOW'; Name = 'Vanadium (jnic /)'; Level = 'H'; Pattern = 'dev/jnic/' }, @{ Cat = 'KLIENCI CHEATOW'; Name = 'Vanadium (jnic .)'; Level = 'H'; Pattern = 'dev.jnic.' }, @{ Cat = 'KLIENCI CHEATOW'; Name = 'Vanadium (jnicLoader)'; Level = 'H'; Pattern = 'jnicLoader' }, @{ Cat = 'KLIENCI CHEATOW'; Name = 'Kausel'; Level = 'H'; Pattern = 'kausel' }, @{ Cat = 'KLIENCI CHEATOW'; Name = 'Dqrkis'; Level = 'H'; Pattern = 'dqrkis' }, # USUNIETE: 'failedtion'. W calym zrodle wystepowalo RAZ, jako 'failedtion/codecs', # w regionie czystych smieci binarnych obok tablicy znakow czcionki i kodu Java2D. # To sklejka dwoch sasiednich ciagow ('...failed' + 'serialization/codecs'), # a nie nazwa klienta - nie ma czego wykrywac. @{ Cat = 'KLIENCI CHEATOW'; Name = 'Anamvmnt'; Level = 'H'; Pattern = 'anamvmnt' }, @{ Cat = 'KLIENCI CHEATOW'; Name = 'Meteor (pakiet)'; Level = 'H'; Pattern = 'meteordevelopment' }, @{ Cat = 'KLIENCI CHEATOW'; Name = 'Starscript (Meteor)'; Level = 'L'; Pattern = 'starscript' }, # Crack (np. zlamana wersja Grima). UWAGA: samo '.crack' jest bezuzyteczne - # trafia w waniliowe klucze Minecrafta (block.minecraft.cracked_nether_bricks, # item.wolf_armor.crack, block.sniffer_egg.crack), czyli u kazdego gracza. # Dzialaja tylko formy z separatorem sciezki/archiwum - zweryfikowane czyste. @{ Cat = 'KLIENCI CHEATOW'; Name = 'Crack (katalog)'; Level = 'L'; Pattern = '/crack/' }, @{ Cat = 'KLIENCI CHEATOW'; Name = 'Crack (plik w jarze)'; Level = 'L'; Pattern = '.crackPK' }, @{ Cat = 'KLIENCI CHEATOW'; Name = 'Crack (pakiet)'; Level = 'L'; Pattern = '.crack.' }, @{ Cat = 'HOOKI I MIXINY'; Name = 'Mixin renderFire'; Level = 'H'; Pattern = 'renderFire(Lorg/spongepowered/asm/mixin/injection/callback/CallbackInfo;)V' }, @{ Cat = 'HOOKI I MIXINY'; Name = 'sendMovementPackets'; Level = 'H'; Pattern = 'Lnet/minecraft/client/network/ClientPlayerEntity;sendMovementPackets()V' }, @{ Cat = 'HOOKI I MIXINY'; Name = 'Shader blur GUI'; Level = 'H'; Pattern = 'GUI_BEFORE_PRE_BLUR0v' }, # 'CoreWindowSite' zamiast 'DestructCoreWindowSite' - jest podciagiem tamtej # i dodatkowo lapie warianty CoreWindowSite::Invoke..., ::remove_..., ...HideComponent. @{ Cat = 'SYGNATURY PAMIECI'; Name = 'CoreWindowSite'; Level = 'H'; Pattern = 'CoreWindowSite' }, # USUNIETE: 'jose4j', 'getX509CertificateSha256Thumbprint', 'EcdsaSECP256K1UsingSha256'. # To nazwy z biblioteki jose4j (JSON Web Token) - w zrodlowych listach wystepuja # jako 'org/jose4j/jwe/...', czyli zwykla sciezka biblioteki. Zawieraja ja # launchery logujace sie na konto Microsoft, dlatego trafialy w proces java.exe # launchera na wielu komputerach. Obecnosc tej biblioteki niczego nie dowodzi. @{ Cat = 'SYGNATURY PAMIECI'; Name = 'setWasTouchingWaterH'; Level = 'H'; Pattern = 'setWasTouchingWaterH' }, @{ Cat = 'SYGNATURY PAMIECI'; Name = 'uv_quad_color'; Level = 'L'; Pattern = 'uv_quad_color' }, @{ Cat = 'SYGNATURY PAMIECI'; Name = 'IORegistryEntry'; Level = 'H'; Pattern = 'IORegistryEntryGetChildEntry' }, @{ Cat = 'SYGNATURY PAMIECI'; Name = 'Sygnatura #1'; Level = 'H'; Pattern = 'LLLeLLCLLL23L3' }, @{ Cat = 'SYGNATURY PAMIECI'; Name = 'Sygnatura #2'; Level = 'H'; Pattern = 'i4fCf.G5.MyZdu^Z2l' }, @{ Cat = 'SYGNATURY PAMIECI'; Name = 'Sygnatura #3'; Level = 'H'; Pattern = 'BW_s_QfMHBRVQSGKa]Z' }, @{ Cat = 'SYGNATURY PAMIECI'; Name = 'Sygnatura #4'; Level = 'H'; Pattern = 'DqFETsH_bDCOcsu' }, @{ Cat = 'SYGNATURY PAMIECI'; Name = 'Sygnatura #5'; Level = 'H'; Pattern = 'yHKHMAYcdi' }, @{ Cat = 'SYGNATURY PAMIECI'; Name = 'Sygnatura #6'; Level = 'L'; Pattern = 'tWJ]yX' }, @{ Cat = 'SYGNATURY PAMIECI'; Name = 'Sygnatura #7'; Level = 'L'; Pattern = 'aaa.bbb' } ) # --- Sygnatury Doomsday (surowe wzorce pamieci) ------------------------------ # Single-quoted here-string: wszystko literalnie (backtick, $, ", ' bez escapowania). # Kazda linia = jeden szukany ciag. Duplikaty usuwane w czasie dzialania. $DOOMSDAY = @' xVl,#WK #@_]D$f7+:!s 8\cW!0voReLAd; Dwm2V[Kw ]yBU]Ick +$_s&BL P pkohge\_ ^Dk_gZblK ![D'W7& YS<3]_$],4 1_dNp&q :b_feVh8WbFW HOEHv3xZ OV$\@jgxo&q1Wv\EW( xiO_kZEdFglDch hn#^K=9e52ijC i2nkhYbY CkN^dlN32F &)KpT!\%* XLwOSiLwav -7=5TxR+d6[3j] xrp6#_h^ N#h$C\Y[L<\w q[HlxCjGqOteW\FdaTD mVQtRYJCLk QEfOGhLDM ClUbCwMCJ^ZAId n,[*aeje 9Lr?[*" WdKtG\n[YB_\a dNaGBibtWfaqO JxkgkyPQS r[R[HZKclxU R]jntXLF] Wb[TloBx dFyrkeI yokosJiM "U`,kGZ8G@URL rKo4mNjg<(!Y^fI^DJ =n>V$dB NW+I+:Lm1TI*mtv&( 3]3+b^sq JZ^A\WH[HL[ JDRvLaSjiw),b a*e2mJhy bxi[wI_srfBl OPobmcf[MP JvHCS"*M36a7 (@jHQ T>2W,EpwdbH aimx'J teX& qdBR&.via Wi[CNhp`[G IGmEr_AWn\ ZOBCi#o -CTjSrSV>uj1Z Ex h( wcmlSiv[mE`Uyp E[YcZADEJdZBS ElBjGpSAMDVa iaDpJPivdmXGDZ` R,CEpZl:.MF$j AtcQpWYE`UhnGt /ZC8sXuRkJ6i5S9*q dn1!O_; "!J(#Z( BkQsWTYbqOVP AJteTVHW ?,#/HS2*a2&AyF] K[Se83$u8M r0$[\a c:V=$K"P#+QO<`Hf=J[ xnAcY]eqGJDtSdmjhJt a6?%C1)a 50!mFty,B`6H[F`ib _f7EB@=SCtE(km ?df&F'c 3D"YKaL-XCE0? VTm\ZWTPN^ueY ynAFC`vqR hrdS`E_AdP y)Y#$/#] BxhbHNt`g cs8?hbJ)/W) YOFXguQiDUs EbpHlUWjlDPvlcRT L;;<**<>L< 3KlFEF % HsvYmnXJbrvk^EM` .`]2S'8P*\ BXM7LE9K 7CTqc(K-i[e]6RH 8iPyo?L!?8+;uH&U -csV1xiXfWlVHR\a9M ^NOJXfrg vTqLhqmjemo` avuKOfIUmAEUQ uJtxDyLtJ`Mh TU\vebgkJdfH !&cWI2d'=<;:98765/.-,(&%$#" AoIBAQCwuKqr9ohNhVqDFOgzV8wI94cemJL4BI9+yvNNrCX7hbvF+Bed/IsFYc7n //W1H3JcN+VvbP2Puq0Glrsl+2VTAgMBAAGjMjAwMA8GA1UdEQQIMAaHBJI7fuAw OgXdn2XTnJqlJxsadPswuF7EkOnPu4YjaiPucJmdX4uZ5Km+LWLWs/8Pr9sqX+OH >HEXJHMJ8= pl = new List(); List ol = new List(); List el = new List(); for (int i = 0; i < targets.Length; i++) { pl.Add(Encoding.ASCII.GetBytes(targets[i])); ol.Add(i); el.Add(0); pl.Add(Encoding.Unicode.GetBytes(targets[i])); ol.Add(i); el.Add(1); } pats = pl.ToArray(); owner = ol.ToArray(); encOf = el.ToArray(); // Kubelkowanie po DWOCH pierwszych bajtach zamiast jednego: przy kilkuset // sygnaturach pojedynczy bajt dawal dziesiatki kandydatow na kazda pozycje // w pamieci i skan trwal ponad dwa razy dluzej. List[] buckets = new List[65536]; maxLen = 2; for (int i = 0; i < pats.Length; i++) { if (pats[i].Length < 2) continue; int key = (pats[i][0] << 8) | pats[i][1]; if (buckets[key] == null) buckets[key] = new List(); buckets[key].Add(i); if (pats[i].Length > maxLen) maxLen = pats[i].Length; } byPair = new int[65536][]; for (int i = 0; i < 65536; i++) byPair[i] = (buckets[i] == null) ? null : buckets[i].ToArray(); buf = new byte[CHUNK]; } public long[][] Regions() { List list = new List(); long addr = 0; // Na 32-bitowym PowerShellu new IntPtr(addr) rzucilby OverflowException. long limit = (IntPtr.Size == 4) ? 0x7FFF0000L : 0x7FFFFFFF0000L; uint sz = (uint)Marshal.SizeOf(typeof(MI)); MI mi; while (addr < limit) { if (VirtualQueryEx(h, new IntPtr(addr), out mi, sz) == 0) break; long rs = mi.RegionSize.ToInt64(); long bas = mi.BaseAddress.ToInt64(); if (rs <= 0) break; uint p = mi.Protect; bool readable = (p == 0x02 || p == 0x04 || p == 0x08 || p == 0x20 || p == 0x40 || p == 0x80); if (mi.State == MEM_COMMIT && readable) list.Add(new long[] { bas, rs }); long next = bas + rs; if (next <= addr) break; addr = next; } return list.ToArray(); } public void Scan(long baseAddr, long size) { long off = 0; while (off < size) { int want = (int)Math.Min((long)CHUNK, size - off); IntPtr read; if (!ReadProcessMemory(h, new IntPtr(baseAddr + off), buf, (IntPtr)want, out read)) { off += want; continue; } int n = (int)read.ToInt64(); if (n <= 0) { off += want; continue; } curBase = baseAddr + off; Search(n); BytesRead += n; int step = n - (maxLen - 1); if (step <= 0) step = n; off += step; } } void Search(int n) { byte[] b = buf; for (int i = 0; i + 1 < n; i++) { int[] cand = byPair[(b[i] << 8) | b[i + 1]]; if (cand == null) continue; for (int k = 0; k < cand.Length; k++) { int pi = cand[k]; int o = owner[pi]; if (Found[o]) continue; byte[] p = pats[pi]; if (i + p.Length > n) continue; int j = 2; // dwa pierwsze bajty zgodne z kubelka while (j < p.Length && b[i + j] == p[j]) j++; if (j == p.Length) { Found[o] = true; Addr[o] = curBase + i; Enc[o] = encOf[pi]; } } } } public void Close() { if (h != IntPtr.Zero) { CloseHandle(h); h = IntPtr.Zero; } } } '@ # ============================================================================= # START # ============================================================================= try { Clear-Host } catch { } Write-Banner Write-Host '' Write-Host ($PAD + ' Ten skrypt tylko ODCZYTUJE pamiec procesu gry i wypisuje wynik.') -ForegroundColor Gray Write-Host ($PAD + ' Nie laczy sie z internetem, nie czyta hasel ani plikow z kontami,') -ForegroundColor Gray Write-Host ($PAD + ' nic nie pobiera i nic nie zapisuje. Cale zrodlo przeczytasz tu:') -ForegroundColor Gray Write-Host ($PAD + ' ' + $SCRIPT_SOURCE) -ForegroundColor Cyan Write-Host '' $sessionId = ([guid]::NewGuid().ToString('N').Substring(0, 8)).ToUpper() $startedAt = Get-Date Box-Top 'SESJA' 'DarkGray' Box-Field 'Kod sesji' $sessionId 'Yellow' Box-Field 'Data i czas' $startedAt.ToString('yyyy-MM-dd HH:mm:ss') Box-Field 'Komputer' ("{0} \ {1}" -f $env:COMPUTERNAME, $env:USERNAME) Box-Field 'PowerShell' ("{0} ({1}-bit)" -f $PSVersionTable.PSVersion, $(if ([Environment]::Is64BitProcess) { 64 } else { 32 })) Box-Bottom # --- Wynik kontroli uczciwosci sesji ----------------------------------------- if ($__integrity.Count -gt 0) { Write-Host '' Box-Top 'KONTROLA SESJI' 'Red' foreach ($m in $__integrity) { Box-Row @(@{ T = (' ' + [string]$G.BAD + ' '); C = 'Red' }, @{ T = (Fit $m ($IN - 5)); C = 'Red' }) 'Red' } Box-Bottom 'Red' Write-Verdict 'SESJA POWERSHELL ZOSTALA ZMANIPULOWANA' 'wynik niewiarygodny - sprawdzenie przerwane' 'DarkRed' 'White' Write-Host ($PAD + ' Zamknij WSZYSTKIE okna PowerShell, otworz nowe i uruchom ponownie.') -ForegroundColor Yellow Write-Host '' Write-Footer $sessionId $startedAt return } $warnings = @() $histCount = 0 try { $histCount = @(Microsoft.PowerShell.Core\Get-History).Count } catch { } if ($histCount -gt 0) { $warnings += "To okno PowerShell bylo juz uzywane ($histCount komend) - uzyj swiezego okna." } if (-not [Environment]::Is64BitProcess) { $warnings += 'To 32-bitowy PowerShell - nie odczyta calej pamieci gry.' } if ($warnings.Count -gt 0) { Write-Host '' Box-Top 'OSTRZEZENIA' 'DarkYellow' foreach ($m in $warnings) { Box-Row @(@{ T = (' ' + [string]$G.WARN + ' '); C = 'Yellow' }, @{ T = (Fit $m ($IN - 5)); C = 'Yellow' }) 'DarkYellow' } Box-Bottom 'DarkYellow' } # --- Kompilacja silnika ------------------------------------------------------- try { Add-Type -TypeDefinition $CS } catch { Write-Verdict 'NIE UDALO SIE PRZYGOTOWAC SKANERA' $_.Exception.Message 'DarkRed' 'White' Write-Footer $sessionId $startedAt return } # --- Procesy gry -------------------------------------------------------------- $procs = @(Get-Process -Name 'javaw', 'java' -ErrorAction SilentlyContinue | Sort-Object -Property WorkingSet64 -Descending) Write-Host '' Box-Top 'PROCESY GRY' 'DarkGray' if ($procs.Count -eq 0) { Box-Row @(@{ T = ' Nie znaleziono procesu javaw.exe / java.exe.'; C = 'Yellow' }) Box-Row @(@{ T = ' Wlacz Minecrafta i uruchom sprawdzanie ponownie.'; C = 'Yellow' }) Box-Bottom Write-Verdict 'BRAK URUCHOMIONEJ GRY' 'sprawdzenie niewykonane' 'DarkYellow' 'Black' Write-Footer $sessionId $startedAt return } Box-Row @( @{ T = (' ' + (Fit 'PROCES' 14)); C = 'DarkGray' }, @{ T = (Fit 'PID' 10); C = 'DarkGray' }, @{ T = (Fit 'PAMIEC' 12); C = 'DarkGray' }, @{ T = 'START'; C = 'DarkGray' } ) foreach ($p in $procs) { # Uwaga: PowerShell 5.1 nie pozwala przypisac wyniku try/catch do zmiennej. $started = '?' try { $started = $p.StartTime.ToString('HH:mm:ss') } catch { } Box-Row @( @{ T = (' ' + (Fit ($p.ProcessName + '.exe') 14)); C = 'White' }, @{ T = (Fit ([string]$p.Id) 10); C = 'Gray' }, @{ T = (Fit ("{0} MB" -f [int]($p.WorkingSet64 / 1MB)) 12); C = 'Gray' }, @{ T = $started; C = 'Gray' } ) } Box-Bottom # --- Skanowanie --------------------------------------------------------------- $patterns = @($SIGNATURES | ForEach-Object { $_.Pattern }) $n = $SIGNATURES.Count $hits = New-Object 'bool[]' $n $hitAddr = New-Object 'long[]' $n $hitEnc = New-Object 'int[]' $n $hitPid = New-Object 'int[]' $n $hitProc = New-Object 'string[]' $n $scanned = 0L $opened = 0 Write-Host '' Write-Host ($PAD + ' SKANOWANIE PAMIECI') -ForegroundColor White Write-Host ($PAD + ' ' + ([string]$G.H * ($W - 2))) -ForegroundColor DarkGray foreach ($p in $procs) { $scanner = [KFB8ED4F88DB9]::Open($p.Id, $patterns) if ($null -eq $scanner) { Write-Host ($PAD + " $($G.WARN) Brak dostepu do PID $($p.Id) - uruchom PowerShell jako administrator.") -ForegroundColor Yellow continue } $opened++ try { $regions = $scanner.Regions() $total = 0L foreach ($r in $regions) { $total += $r[1] } if ($total -le 0) { $total = 1 } $label = "{0} (PID {1})" -f $p.ProcessName, $p.Id $t0 = Get-Date $done = 0L $lastPct = -1 foreach ($r in $regions) { $scanner.Scan($r[0], $r[1]) $done += $r[1] $pct = [int](100 * $done / $total) if ($pct -ne $lastPct) { Show-Progress $pct $label ([int]($scanner.BytesRead / 1MB)) ((Get-Date) - $t0).TotalSeconds $lastPct = $pct } } Show-Progress 100 $label ([int]($scanner.BytesRead / 1MB)) ((Get-Date) - $t0).TotalSeconds Write-Host '' $found = $scanner.Found for ($i = 0; $i -lt $n; $i++) { if ($found[$i] -and -not $hits[$i]) { $hits[$i] = $true $hitAddr[$i] = $scanner.Addr[$i] $hitEnc[$i] = $scanner.Enc[$i] $hitPid[$i] = $p.Id $hitProc[$i] = $p.ProcessName } } $scanned += $scanner.BytesRead } finally { $scanner.Close() } } if ($opened -eq 0) { Write-Verdict 'BRAK DOSTEPU DO PAMIECI GRY' 'uruchom PowerShell jako administrator' 'DarkYellow' 'Black' Write-Footer $sessionId $startedAt return } # --- Wyniki ------------------------------------------------------------------- $OK_TXT = '[ CZYSTO ]' $BAD_TXT = '[ WYKRYTO ]' $SUS_TXT = '[ PODEJRZANE ]' Write-Host '' Box-Top 'WYNIKI' 'DarkGray' Box-Row @( @{ T = (' ' + (Fit 'SYGNATURA' 22)); C = 'DarkGray' }, @{ T = (Fit 'SZUKANY KOD' 34); C = 'DarkGray' }, @{ T = ' STATUS'; C = 'DarkGray' } ) function Write-SigRow([hashtable]$Sig, [bool]$Hit) { if ($Hit) { if ($Sig.Level -eq 'H') { $status = $BAD_TXT; $sc = 'Red'; $mark = $G.BAD; $mc = 'Red' } else { $status = $SUS_TXT; $sc = 'Yellow'; $mark = $G.WARN; $mc = 'Yellow' } $nameColor = 'White' } else { $status = $OK_TXT; $sc = 'Green'; $mark = $G.OK; $mc = 'DarkGreen'; $nameColor = 'Gray' } Box-Row @( @{ T = (' ' + [string]$mark + ' '); C = $mc }, # 19 + wymuszona spacja: przy nazwie dokladnie 20-znakowej kolumny # zlewalyby sie ze soba bez odstepu. @{ T = ((Fit $Sig.Name 19) + ' '); C = $nameColor }, @{ T = (Fit $Sig.Pattern 34); C = 'DarkGray' }, @{ T = (' ' + $status); C = $sc } ) } $hi = 0; $lo = 0 $i = 0 while ($i -lt $n) { $cat = $SIGNATURES[$i].Cat Box-Sep Box-Row @(@{ T = (' ' + $cat); C = 'Cyan' }) if ($SIGNATURES[$i].Bulk) { # Kategoria zbiorcza: pokazujemy tylko trafienia + podsumowanie reszty. $catStart = $i $catHits = @() while ($i -lt $n -and $SIGNATURES[$i].Cat -eq $cat) { if ($hits[$i]) { $catHits += $i } $i++ } $catTotal = $i - $catStart foreach ($hidx in $catHits) { if ($SIGNATURES[$hidx].Level -eq 'H') { $hi++ } else { $lo++ } Write-SigRow $SIGNATURES[$hidx] $true } $clean = $catTotal - $catHits.Count if ($catHits.Count -eq 0) { Box-Row @( @{ T = (' ' + [string]$G.OK + ' '); C = 'DarkGreen' }, @{ T = ("wszystkie {0} sygnatur czyste" -f $catTotal); C = 'Green' } ) } else { Box-Row @( @{ T = (' ' + [string]$G.OK + ' '); C = 'DarkGreen' }, @{ T = ("pozostale {0} z {1} sygnatur czyste" -f $clean, $catTotal); C = 'Gray' } ) } } else { while ($i -lt $n -and $SIGNATURES[$i].Cat -eq $cat) { Write-SigRow $SIGNATURES[$i] $hits[$i] if ($hits[$i]) { if ($SIGNATURES[$i].Level -eq 'H') { $hi++ } else { $lo++ } } $i++ } } } Box-Sep $elapsed = (Get-Date) - $startedAt Box-Row @( @{ T = ' Przeskanowano '; C = 'DarkGray' }, @{ T = ("{0} MB" -f [int]($scanned / 1MB)); C = 'White' }, @{ T = ' w '; C = 'DarkGray' }, @{ T = ("{0:N1} s" -f $elapsed.TotalSeconds); C = 'White' }, @{ T = ' sygnatur: '; C = 'DarkGray' }, @{ T = [string]$n; C = 'White' }, @{ T = ' trafien: '; C = 'DarkGray' }, @{ T = [string]($hi + $lo); C = $(if ($hi + $lo -gt 0) { 'Red' } else { 'Green' }) } ) Box-Bottom # --- Dowody ------------------------------------------------------------------- if ($hi + $lo -gt 0) { Write-Host '' Box-Top 'DOWODY' 'Red' $k = 0 for ($i = 0; $i -lt $n; $i++) { if (-not $hits[$i]) { continue } $k++ $sig = $SIGNATURES[$i] $col = $(if ($sig.Level -eq 'H') { 'Red' } else { 'Yellow' }) if ($k -gt 1) { Box-Sep 'Red' } Box-Row @( @{ T = (" {0}. " -f $k); C = 'DarkGray' }, @{ T = (Fit $sig.Name 24); C = $col }, @{ T = $(if ($sig.Level -eq 'H') { 'pewne wykrycie' } else { 'poszlaka - do weryfikacji recznej' }); C = 'DarkGray' } ) 'Red' Box-Row @( @{ T = ' proces '; C = 'DarkGray' }, @{ T = ("{0}.exe (PID {1})" -f $hitProc[$i], $hitPid[$i]); C = 'White' } ) 'Red' Box-Row @( @{ T = ' adres '; C = 'DarkGray' }, @{ T = ("0x{0:X16}" -f $hitAddr[$i]); C = 'White' }, @{ T = (' kodowanie: ' + $(if ($hitEnc[$i] -eq 1) { 'UTF-16' } else { 'ASCII' })); C = 'DarkGray' } ) 'Red' Box-Row @( @{ T = ' kod '; C = 'DarkGray' }, @{ T = (Fit $sig.Pattern ($IN - 15)); C = 'Gray' } ) 'Red' } Box-Bottom 'Red' } # --- Werdykt ------------------------------------------------------------------ if ($hi -gt 0) { Write-Verdict ("WYKRYTO CHEATY ({0})" -f $hi) 'szczegoly znajdziesz w sekcji DOWODY' 'DarkRed' 'White' } elseif ($lo -gt 0) { Write-Verdict ("PODEJRZANE ({0})" -f $lo) 'krotkie sygnatury - wymagaja recznej weryfikacji' 'DarkYellow' 'Black' } else { Write-Verdict 'CZYSTO' ("nie znaleziono zadnej z {0} sygnatur" -f $n) 'DarkGreen' 'White' } Write-Footer $sessionId $startedAt