2009-01-16:

Supportu dla ANSI escape codes w cmd.exe i skryptach BAT

windows:bat:re:winapi:easy:asm:c:c++
Begin teh Update
Widziałem tu i tam kilka komentarzy że są problemy z uruchomieniem u siebie ansihacka. Przede wszystkim po odpaleniu patchera należy sprawdzić czy utworzył się plik _cmd.exe, i czy patcher na konsoli (najlepiej go z konsoli właśnie odpalać) wypisał wszędzie OK, i nie pojawił się żaden ERROR. Jeżeli plik postaw, i są wszędzie OK, to trzeba odpalić _cmd.exe i napisać ver. Powinna wyświetlić się informacja o wersji Windowsa, z dopisaną linią Ansi hack ver 0.004b by gynvael.coldwind//vx. Jeżeli ta linia się pojawi, to hack działa (linia jest dodawana dokładnie w tej samej funkcji w której ANSI jest realizowane). Jeżeli się nie pojawi, to piszemy mejla lub komentarz do mnie, a ja staram się wymyślić co zepsułem ;D
End of Update

Kiedyś, sto lat temu, tj. w czasach DOS-a, była możliwość tworzenia kolorowych promptów, pisania na kolorowo po ekranie, etc. A to wszystko dzięki ANSI escape codes - krótkim, paro znakowym wyrażeniom, których wypisanie na "ekranie" powodowało zmianę koloru, przeniesienie kursora, czy np. wyczyszczenie ekranu. ANSI escape codes miały się całkiem dobrze pod DOSem, całkiem nieźle miały się również w czasach Windowsa 95 i 98. Niestety, wraz z nadejściem rodziny NT, obsługa ANSI wyparowała z konsoli (została tylko w command.com, który jak wiadomo jest 16-bitowy i działa pod NTVDM, które ofc na 64-bitowych Windowsach nie działa w ogóle). (krótki offtopic: na *nixach ANSI escape codes były zawsze, i są do dzisiaj).

Osobiście bardzo zwlekałem z opuszczeniem Windowsa 98, i przesiadką na XP. Powody były różne, głównie związane z dowcipami (które miały niestety pokrycie w rzeczywistości przed SP2) typu "ile sekund potrzeba na zainfekowanie Windowsa XP od momentu podłączenia do Internetu". No, ale w końcu nadszedł SP2, i nawet ja (diehard fan 9x i DOSa) zdecydowałem się przesiąść na rodzinkę NT. Po instalacji Windowsa przerzuciłem swój skrypt .BAT który zawsze był odpalany w momencie uruchomienia command.com (afair .PIFem to rozwiązałem), odpaliłem cmd.exe, i... zamiast ślicznego kolorowego loga "WIND" ujrzałem "krzaki". Zrozpaczony wyREMowałem logo, i kontynuowałem instalację...

Do sprawy wróciłem po jakimś roku, po stwierdzeniu że dalej na dwu kolorowej konsoli nie dam rady (osobiście bardzo lubię korzystać z konsoli, i zawsze mam przynajmniej parę okien odpalonych). Po kilku godzinach miałem stworzonego patcha do cmd.exe, który pozwalał na użycie ANSI Escape Code'ów w wewnętrznych poleceniach konsoli (ECHO, TYPE, PROMPT, etc). Patch nawet wrzuciłem na techbloga. Potem hosting gdzie był techblog padł, i patch zniknął z netu.

Z uwagi na stosunkowo duże zainteresowanie skryptami .BAT w ciągu ostatnich 3ch dni (ponad 10tys odwiedzin w 3 dni, huh), stwierdziłem że jest całkiem niezły moment żeby patch znowu wrzucić na net ;>

kolorowy obrazek


OK, jak to wszystko działa (źródła + binarki na końcu posta, jak zwykle, tym razem licencja GPL).
Interpreter, aka cmd.exe, wypisuje tekst na konsole za pomocą funkcji API WriteConsoleW. Tak więc stworzenie hooka na to polecenie w kontekście cmd.exe spowoduje że każdy tekst który cmd.exe będzie chciał wypisać, przejdzie przez naszą funkcję. Nasza funkcja powinna po prostu implementować ANSI Escape Codes, tj wykrywać kod ucieczki (ASCII nr 27), a następnie reagować wg. "polecenia" które się po nim znajduje. Moja implementacja (zawarta w AnsiSupport.c) jest w większości kompatybilna z oryginalnymi ANSI Escape Codes, natomiast jest też parę zmian (pisałem to pod siebie, więc zależało mi bardziej na funkcjonalności niż na kompatybilności). Oto jakie "polecenia" ANSI zawiera moja implementacja:

Oryginalne ANSI:

m - zmiana koloru
H lub f - zmiana pozycji kursora
A - przesunięcie kursora w górę
B - przesunięcie kursora w dół
C - przesunięcie kursora w prawo
D - przesunięcie kursora w lewo
s - zapis pozycji kursora
u - powrót do pozycji kursora
2J - wyczyszczenie ekranu
K - wyczyszczenie linii

Moje "rozszerzenia":
X - wrzucenie obecnego koloru na stos kolorów
x - zdjęcie koloru ze stosu
Y - zapis koloru w tablicy na podanej pozycji (tablica != stos w tym wypadku)
y - odczyt koloru z tablicy
t - początek tytułu (chodzi o tytuł okna konsoli)
T - koniec tytułu

Offtopic: w sumie można by tutaj wrzuć implementację OpenGL :D

Nie będę tutaj opisywał implementacji każdego kodu, wszystko jest w źródłach, które moim zdaniem są bardzo proste. Warto w nie zajrzeć choćby po to żeby zobaczyć jak dokładnie można każdego kodu użyć ;>

Jeżeli chodzi o samą metodę działania patchera, to sprawa wygląda tak:
1. Po uruchomieniu patcha (ansihack.exe) robi on kopię cmd.exe do obecnego katalogu jako _cmd.exe, i otwiera ów plik do zapisu
2. Sprawdza obecność plików DllSpoof.dll i AnsiSupport.dll - te pliki należy potem wrzucić do katalogu systemowego (c:\windows\system32)
3. Pobiera OEP cmd.exe
4. Ustawia flagę IMAGE_FILE_RELOCS_STRIPPED (lojalnie ostrzegam że wstawienie tej flagi spowoduje że cmd.exe na systemach z rodziny Visty nie będzie współpracował z mechanizmem randomizacji przestrzeni adresowej (aka ASRL), czyli będzie ładowany ZAWSZE pod ten sam adres, co tak na prawdę totalnie nic nie zmienia ;p, tylko ułatwia patchowanie)
5. Zwiększa wielkość ostatniej sekcji, ustawia jej flagi Read/Write/Execute (co nie do końca jest ładne, ale wystarczy)
6. Kopiuje krótki kod który ładuje biblioteke AnsiSupport.dll do ostatniej sekcji i zmienia EP na tenże kod (kod po załadowaniu biblioteki skacze na OEP - niektóre antywirusy mogą być nieszczęśliwe że to jest tak zrobione, ale to problem ich heurystyki a nie samego patcha)
7. _cmd.exe jest zapisywany

Po odpaleniu patcha powinien powstać pliczek _cmd.exe. Należy teraz go uruchomić, wejść do katalogu tests, i odpalić np. slogo.bat. Jeżeli wyświetli się ładne kolorowe logo, to jesteśmy w domu. W innym wypadku możecie trochę podebuggować, albo napisać mejla ;>

Teraz możemy np. skopiować _cmd.exe do katalogu systemowego (razem z DLLkami), i albo podmienić cmd.exe (winda ma zwyczaj ten pliczek przywracać, albo nadpisywać przy aktualizacjach, więc raczej nie polecam), albo użyć np. poniższego klucza znajdującego się w rejestrze:

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\cmd.exe]
"Debugger"="c:\\windows\\system32\\_cmd.exe %*"


Powoduje on że zamiast cmd.exe zostanie odpalony _cmd.exe.

No, i chyba tyle na dzisiaj. Miłej zabawy z promptem etc.

Dodam jeszcze na koniec że ten wykorzystanie tego patcha pozwala na użycie ANSI Escape Codes TYLKO W RAMACH CMD.EXE i skryptów BAT/CMD. Wprowadzenie obsługi ANSI Escape Codes do wszystkich aplikacji, wymagałoby patcha na CSRSS.EXE, a konkretniej w basesrv.dll/csrsrv.dll/winsrv.dll (nie pamiętam już w której to DLLce siedziała implementacja okna konsoli).

cmd_ansihack_004c.zip (46kb, źródła + binarki) !!! używasz na własne ryzyko !!!

Comments:

2009-01-16 05:02:04 = Malcom
{
Niezly patch ;)
Wczoraj jakos mi przewinela sie mysl, ze milo byloby napisac cos, aby tab nie tylko dopelnial nazwy plikow/sciezki, ale takze komendy, jak to bywa w unixowych systemach.
}
2009-01-16 07:18:53 = Patrykuss
{
Cóż... Nie ukrywajmy. Następny ciekawy wpis dot. plików wsadowych. Nie tak dawno rozmawialiśmy nawet o problemie "kolorowania" w batach ;).

Muszę przyznać, że ostatnio wpadłem na łatwiejszy ale i prostszy sposób na pseudokolorowanie składni batcha. Oczywiście nie będę go nawet porównywał z Twoim, bo byłoby to dla mnie kompromitujące :D.
}
2009-01-16 12:10:14 = mt3o
{
Nie, żebym był złośliwy, ale ta popularność jest tylko chwilowa. Trafiłeś z wpisem o obiektowości w plikach bat na wykop i pewnie wiele innych serwisów tego typu. Ponadto wiele osób poleciło twoje notki znajomym. Za kilka dni sytuacja wróci do normy ;) Część gości niewątpliwie będzie tutaj zaglądać, ale to tylko mały procent. Gdy to był mój blog, cieszyłbym się, że wytrzymał taki duży napływ osób odwiedzających. Sporo witryn siada po ukazaniu się na wykopie :]

Pozdrawiam
mt3o
}
2009-01-16 12:37:11 = Gynvael Coldwind
{
@Malcom
Taa, taby są następne na mojej liście modyfikacji cmd.exe ;> Może uda się je w końcu skodzić ;>

@Patrykuss
Mógłbyś podać sposób o którym mówisz? Każde działające (choćby częściowo) rozwiązanie jest dobre, a szczególnie jeżeli nie wymaga patchowania cmd.exe ;D

@mt3o
W tym co napisałeś nie widzę nic złośliwego ;> Akurat pisząc o zwiększonej popularności miałem właśnie na myśli ten mały procent osób które będą wracać (np Ciebie ;>, to twój drugi komentarz, pod innym postem ;>)
O wykopie ofc wiem, pik na wykresie był niezły ;>


}
2009-01-17 02:10:54 = Patrykuss
{
Zajrzyj do archiwum psi/gg (nie pamiętam). Tutaj nie będę pisał otwarcie bo chcę opublikować ten sposób na swoim blogu ;). Niech ja tylko naprawię swojego wxDev i biorę się do roboty ;).
}
2009-01-17 12:45:06 = Gynvael Coldwind
{
@Patrykuss
OK poszperam.. faktycznie coś mówiłeś ;>
Jak opublikujesz to daj znać ;>
}
2009-01-19 02:37:32 = kicaj
{
w porównaniu z OpenGl, to - to już jest trochę naciągane, batch powinnien działać jako sam skrypt, bez zbędnych dodaktów, a co do kolorków to chyba by było już łatwiej zrobić aplikację która by się nazywała ECHOC i opowiednia parsowała przyjęte ciągi. Zawsze można skorzystać z programu DEBUG, do wygenerowania prostego coma który bo robił taką aplikację w locie, jeśli by nie istniała.

btw, czy istnieje w cmd coś takiego jak 'choice' z opóźnionym wywołaniem opcji?
}
2009-01-19 03:17:58 = Gynvael Coldwind
{
@kicaj
Dzięki za komentarz ;>
Hehe ja bym powiedział odwrotnie. Że OpenGL jest naciągany, zresztą, zauważ że też potrzebował dodatki (aka GLDaemon.exe + SDL.dll i GLOpcode.exe).

Po za tym wyżej nie przedstawiam "jak uzyskać kolorki w BAT", tylko "jak dodać obsługę ANSI Escape Codes do cmd.exe" - to jest coś zupełnie innego niż poprzednie dwa tematy, ponieważ dotyczy bezpośrednio cmd.exe, a nie samych skryptów BAT (BAT owszem dotyczy, ale prawie że jako efekt uboczny ;>). Zauważ że zaznaczyłem też że nie chodzi mi o kompatybilność, tylko o funkcjonalność.

Co do ECHOC, niby OK, ale jak byś np. użył ECHOC do stworzenia kolorowego prompt'a? Zauważ że PROMPT Windowsowy w przeciwieństwie do analogicznego prompta *nixowego, nie ma możliwości uruchamiania żadnych zewnętrznych aplikacji - stąd potrzeba zadziałania wewnątrz interpretera ;>

Co do DEBUG. Debug działa pod NTVDM. Owszem, można dropnąć dowolną binarkę (do 64kb) korzystając z DEBUG, ale.. jak wspomniałem, NTVDM, czyli np. na mojej 64-bitowej Viście DEBUG najzwyczajniej w świetnie nie zadziała (poniżej komunikat):

---------------------------
Nieobsługiwana aplikacja 16-bitowa
---------------------------
Nie można uruchomić programu lub funkcji ??c:windowscommandDEBUG.EXE albo ten program lub funkcja nie działa z powodu niezgodności z 64-bitowymi wersjami systemu Windows. Skontaktuj się z dostawcą oprogramowania, aby uzyskać informacje, czy jest dostępna wersja zgodna z 64-bitowymi systemami Windows.

(CMD.EXE nawet na 64-bitowym OSie jest 32-bitowy, więc patch jest w tej kwestii w miarę uniwersalny)

Co do choice, hmm, nie za bardzo rozumiem "opóźnione wywołanie opcji", natomiast może trafię odpowiedzią w twoje pytanie (jeżeli nie trafiłem, to postaraj się wyjaśnić o co chodzi ;>).
W cmd.exe jest set /p zmienna=zapytanie od tego. Np.:

--code--

@echo off
setlocal ENABLEEXTENSIONS
setlocal ENABLEDELAYEDEXPANSION
echo 1 - Opcja 1
echo 2 - Opcja 2
echo 3 - Opcja 3
set /p opcja="Podaj opcje: "

echo Wybrano opcje: !opcja!

if "!opcja!"=="1" (
echo IMPLEMENTACJA OPCJI 1
goto :EOF
)
if "!opcja!"=="2" (
echo IMPLEMENTACJA OPCJI 2
goto :EOF
)
if "!opcja!"=="3" (
echo IMPLEMENTACJA OPCJI 3
goto :EOF
)
echo Dziwna ta opcja ^^_-
goto :EOF

--KONIEC code--

O coś takiego ci chodziło ?
}
2009-01-19 06:24:59 = kicaj
{
w pewnym sensie masz rację, ale wtedy to pozostaje już tylko sztuką dla sztuki, jak ktoś to wcześniej powiedział

co do CHOICE, w cmmand wyglądało to tak:
CHOICE [ /C[:]choices ] [ /N ] [ /S ] [ /[:]c,nn ] text

oczywiście listę parametrów można zrobić i sprawdzać czy wpisany ciąg należy do niej ale mi chodziło o paramert /T[:]c,nn gdzie po upływie paru sekund nn sam "wciska" klawisz "c", w command jak dobrze pamiętam to też było rozwiązane przez zewnętrzny program, więc nie oczekuję że w tej wersji shella coś innego by zrobili, ale może Ty jako masta of hack znasz jakiś magiczny sposób
}
2009-01-19 10:14:25 = Gynvael Coldwind
{
Ano właśnie imho patch wyżej nie jest sztuką dla sztuki - ja go używam, jeszcze kilku znajomych go używa, etc. Czego nie można powiedzieć o BAT obiektowym czy OpenGL ;> Te dwa ostatnie to sztuka dla sztuki ;>

Co do CHOICE, to z tego co widzę nadal jest takie polecenie w nowych wersjach Windowsa (Vista, nie wiem czy na XP też).

20:10:17 gynvael >choice /?
CHOICE [/C wybory] [/N] [/CS] [/T limit_czasu /D wybór] [/M tekst]
}
2009-01-19 11:25:54 = Patrykuss
{
W Windowsie XP (bynajmniej u mnie) niestety choice nie ma jednak nic nie stoi na przeszkodzie znalezienia takowego w Sieci lub nakodzenia sobie na kolanie ;).
}
2009-01-19 13:59:10 = Gynvael Coldwind
{
Hmm.. A to złośliwy XP ;>
Niestety, nic zastępczego w takim razie nie przychodzi mi do głowy ;<
}
2010-05-03 13:45:50 = Mr_KrzYch00
{
Wyglada na to, ze _cmd.exe, ktory jest spatchowanym plikiem cmd.exe po uruchomieniu ansihacka, znajdujacy sie w katalogu z ansihackiem i DLLami NIE DZIALA na Windowsie 7 Home Premium x64. Po pojawieniu sie czarnego okienka konsoli z kursorem wyskakuje informacja, ze wystapil blad i windows szuka rozwiazania =D ["Windows Command Processor has stopped working"]. Dodatkowe informacje: Antywirus wylaczony =P
}
2010-05-08 10:18:03 = Gynvael Coldwind
{
@Mr KrzYch00
Hmm, a to ciekawe... patchujesz wersje 32 czy 64 bitową cmd.exe (pod x86-64 są obie)?
Anyway, mi na Windows 7 Ultimate x86-64 PL działa OK...
}
2010-07-04 08:54:39 = Agares
{
U mnie pod Win7 Professional x86-32 to samo co u Mr_KrzYch00 + w podglądzie zdarzeń:
Nazwa aplikacji powodującej błąd: _cmd.exe, wersja: 6.1.7600.16385, sygnatura czasowa: 0x4a5bc19e
Nazwa modułu powodującego błąd: unknown, wersja: 0.0.0.0, sygnatura czasowa: 0x00000000
Kod wyjątku: 0xc0000005
Przesunięcie błędu: 0x00000000
Identyfikator procesu powodującego błąd: 0x1684
Godzina uruchomienia aplikacji powodującej błąd: 0x01cb1b55c8eacdcc
Ścieżka aplikacji powodującej błąd: D:DOCSDocumentscmd_004c\_cmd.exe
Ścieżka modułu powodującego błąd: unknown
Identyfikator raportu: 06a216dd-8749-11df-90d3-d8219c1015c5
}
2011-01-12 20:17:05 = MDobak
{
Jeśli ktoś przegląda takie archiwalne już wpisy... w sieci wygrzebałem fajny kod, implementujący ANSII Escape Codes do dowolnej aplikacji, kod ma trochę niedoróbek i błędów ale nie są trudne do zlokalizowania ;) O ile dobrze pamiętam, to z takich większych błędów nie można ustawić tła, ale można jakoś prosto to naprawić... mi się udało ;p
http://www.programmersheaven.com/download/16630/download.aspx
}
2013-06-08 09:59:05 = mazak
{
a w jaki sposób wykorzystać klawisz ESC do zakończenia skryptu czy w ogóle da się :) nie używając przy tym żadnych zewnętrznych modułów ??po prostu [ESC] i okienko sie zamyka :) oczywiście wkomponować :) w to set :) i pętle :) by brys [ESC] i koniec po mimo ze set czeka na podanie wartości niby proste :) ale ... :) nooo właśnie :) ale
}

Add a comment:

Nick:
URL (optional):
Math captcha: 6 ∗ 9 + 2 =