Long, long time ago, in the DOS times that is, one could configure the command prompt to be colorful, one could echo colorful messages, etc. And one could do all that thanks to the ANSI escape codes - short commands echoed to the "screen" (stdout/stderr that is) that caused the colors to change, the cursor to move, or the screen to be cleaned. ANSI escape code well working quite well in DOS, and they even worked in Windows 95/98. However, with the arrival of the NT family, the ANSI support in the console ceased to exist (well, it was still available in the command.com interpreter, but it's 16-bit running under NTVDM, what makes it not the best choice, not to mention that the NTVDM is not available in the 64-bit Windows versions). (A short offtopic: on *nix systems ANSI escape code well available almost always, and they are still available today).

Since I was a die hard fan of Windows 98, I delayed the upgrade to XP as long as I could. There were some reasons, most has something to do with the common joke (originating from the times before SP2) - "how many seconds does it take for a newly installed XP to be infected after connecting it to the Internet?". But then, the SP2 came, and I finally decided to move to the NT family. After installing Windows I've setup my .BAT script (that always starts after starting a console - it setups some env variables and displays a colorful "WIND" logo), I've run cmd.exe, and... instead of my lovely colorful "WIND" logo I've saw "bushes". Sadly, I had to REM-out the logo (and all other colors from my script), and continue setting up the system...

I got back to this topic a year later, after figuring out (one again) that a two-color console just isn't the thing I want (I use the console frequently - I have at least a few console windows opened all the time), I decided to do something about it.

After a few hours, I had a cmd.exe patch ready. I allowed to use ANSI Escape Codes in the internal cmd.exe commands (ECHO, TYPE, PROMPT, etc). I have even put the patch on my techblog (not this one, it was a few years ago). But then, the hosting with my old techblog was shutdown, and the patch vanished into the mists of history.

Until today, when I decided to repost it again ;>

colorful image of a console


OK, how does it all work (offtopic: sources + binaries are, as always, at the end of this post... GPL this time).

The interpreted, aka cmd.exe, outputs the text on the console using API function WriteConsoleW. So, creating a hook on this function in the context of cmd.exe will make every text written out by cmd.exe to be transfered into our function. The function will just implement ANSI Escape Codes - it will detect the escape code (ASCII no. 27), parse the command, and react to it accordingly. My implementation (placed in AnsiSupport.c) is mostly compatible with the original ANSI Escape Codes, however there are a few changes (well, I've made it for myself, so I figured that functionality is more important than compatibility). I have implemented the following ANSI "commands":

Original ANSI:

m - color change
H or f - cursor position change
A - move the cursor one line up
B - move the cursor one line down
C - move the cursor one line right
D - move the cursor one line left
s - save the cursor position
u - recall the cursor position
2J - clear screen
K - clear line

My "extensions":
X - push the current color on the color stack
x - pop the color from the stack
Y - save the color at the given index in the color table (table != stack)
y - recall the color from the table
t - start of the console title (window title, I use it to output the current directory in the prompt to the window title)
T - end of title

Offtopic: hehe this is a good place to include the OpenGL implementation ;D (see my previous post)

I won't describe here the ANSI implementation, since it's very easy imho. One should consider looking into the sources anyway, to know how to use each escape code, and how do they work ;>

As for the patching process, it works this way:
1. After executing ansihack.exe (the patcher) it will make a copy of cmd.exe (from the system32 directory) to the current working directory as _cmd.exe, and it will open it for writing
2. It checks for existence of DllSpoof.dll and AnsiSupport.dll files (one needs to copy these files to the system32 directory later)
3. It finds the OEP of cmd.exe
4. It sets the IMAGE_FILE_RELOCS_STRIPPED flag (important: setting this flag under Vista and later will cause the address space randomization (aka ASRL) to be turned off for cmd.exe image - it will be loaded ALWAYS on the same address... which really changes nothing ;p, but makes things easier for debugging and patching)
5. It increases the size of the last section, and sets it Read/Write/Execute flags (it's not to beautiful, but it's sufficient)
6. It copies a short code to the last section - the code will load the AnsiSupport.dll library. It also changes the EP to the appended code (after the code loads the library, it jumps to OEP - some AV software might not be to happy about it, but who cares, just turn on the ignore on this file)
7. The forged brand new _cmd.exe is stored

So, after running the patch (I suggest running the patch in a console), there should be a new file in the directory called _cmd.exe. Now, one should execute this file, and enter the tests directory, and run some tests, for example slogo.bat. If a colorful logo shows up, then everything went correct. In any other case, one can debug it a little, or write me an e-mail ;>

Now one can copy the _cmd.exe to the system directory (remember to copy both DLL files!), and either replace the cmd.exe (I would not recommend it, make a copy if you insist, and remember that Windows loves to replace this file at update or finding out that it has changed), or use the following registry "hack":

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


This causes the _cmd.exe to be run when someone wants to execute cmd.exe.

And thats all for today. Have fun with setting up a colorful prompt ;>

One more thing. This patch allows using ANSI Escape Codes only IN THE CONTEXT OF CMD.EXE (including BAT/CMD scripts). Making a global ANSI Escape Codes support would require a patch for CSRSS.exe, or one of it's DLLs - basesrv.dll/csrsrv.dll/winsrv.dll (excuse my memory, I don't remember where is the console window implementation placed).

cmd_ansihack_004c.zip (46kb, sources + binaries) !!! USE AT YOUR OWN RISK ! YOU HAVE BEEN WARNED !!!

Comments:

2009-02-26 01:53:11 = lallous
{
Excellent!
}
2009-03-01 23:05:49 = Gynvael Coldwind
{
@lallous
Glad u like it ;>
}
2009-06-09 06:03:58 = Hossy
{
I ran your "hack" and it created the _cmd.exe. Everything works except for when I first launch it, I get the following messages:

The system cannot find message text for message number 0x2350 in the message fil
e for Application.

The system cannot find message text for message number 0x2334 in the message fil
e for Application.
}
2009-06-09 09:06:36 = Gynvael Coldwind
{
@Hossy
This is normal on Vista and Win7 systems - afaic it is related to the localized string mechanics on these systems, that are bound to both exe name and path.
When you copy the _cmd.exe to c:windowssystem32 and rename it as cmd.exe, everything should work OK (if it doesn't, let me know) ;>
}
2009-09-01 07:29:03 = selyb
{
or in the localization folder (e.g. %windir%system32en-us) create a symlink from _cmd.exe.mui to cmd.exe.mui
or copy cmd.exe.mui to _cmd.exe.mui

either way, _cmd.exe must reside in %windir%system32
}
2009-10-01 05:16:14 = Rufus Kako
{
Hi there.
I'm having troubles making your hack work with anything but your examples.
Looking through the code I think I found something which *could* be causing trouble:
In the file AnsiSupport.c, at line 27 you say:
... && i + 2 < nNumberOfCharsToWrite && ...
I'm wondering what's going to happen if someone decides to write in smaller (say, 1 byte) chunks to the console...?
Maybe that's what wrong, maybe not.
The program I'm trying to run is "hoogle" (http://haskell.org/haskellwiki/Hoogle) with its colour option on.

Thank you for a great hack, please let me know if there's a way around this (I'll be checking this page regularly)


Regards.
}
2009-10-06 14:54:33 = Gynvael Coldwind
{
@Rufus_Kako
Hi!

Hmm, you are saying that you are trying to run an external program, and that is the problem. As I've written before, this hack is for cmd.exe only, and it adds the ANSI support only to cmd.exe, not to the entire console. So I guess you won't be able to use this hack with Hoogle, unless you apply it directly to Hoogle or to the entire console (CSRSS). However in the current state non of this is supported by my patcher or the hack itself (maybe in the future).

Take care!
}
2009-10-18 02:57:59 = nyteschayde
{
I ran this under Windows 7 64-bit. I am not sure if it's a 64-bit issue or other but when executing the generated _cmd.exe from either the creation location or C:WindowsSystem32 it crashes immediately.

Help?!

Output from ansihack

$ ansihack.exe
cmd.exe Ansi Patch ver.0.00c by gynvael.coldwind//vx (2009)
Checking DllSpoof.dll... OK
Checking AnsiSupport.dll... OK
Getting system directory... C:Windowssystem32
Acquiring a copy of cmd.exe... OK
Opening _cmd.exe... OK
Getting OEP... 0000921A
Adding IMAGE_FILE_RELOCS_STRIPPED flag... OK
Resizeing last section and changing EP... OK
Getting address of LoadLibraryA in IAT... 00833838
Injecting AnsiSupport.dll loader... OK
Saving... OK
Done.
}
2009-10-18 12:06:38 = Gynvael Coldwind
{
@nyteschayde
Hmm, that's strange. I've tested it on Windows 7, and it seemed to work. I'll look into the issue later, thank you for the report ;>
Could you tell me what Windows 7 version do you have (language / type).
}
2010-02-17 09:14:45 = bobman
{
Same thing here on Windows 7 64 bit, crashes immediately no matter what.
}
2010-02-18 02:27:43 = derdoc
{
Tried it on Vista/x64. The patching works and resulting _cmd works if started from same dir.
But as soon as I copy it to system32 it does not work anymore.
The issues with "String not found in..." did indeed resolve itself when I renamed it to cmd.exe.
But escape sequences are not interpreted anymore. I also copied both DLLs to system32.
Do all these files have special permissions or a special file owner, like SYSTEM, to work?
Is there any way I can debug it?

If you could also share with us, what is your prompt string for your screenshot above?
I would like to have things like path, date, username or exitcode - if that makes sense in windooze - in my prompt.

Thx,
-dD
}
2010-03-29 17:02:32 = Daniel
{
I'm having the same issue under Win7 Professional x64 (English). The output was:
cmd.exe Ansi Patch ver.0.00c by gynvael.coldwind//vx (2009)
Checking DllSpoof.dll... OK
Checking AnsiSupport.dll... OK
Getting system directory... C:Windowssystem32
Acquiring a copy of cmd.exe... OK
Opening _cmd.exe... OK
Getting OEP... 000060DC
Adding IMAGE_FILE_RELOCS_STRIPPED flag... OK
Resizeing last section and changing EP... OK
Getting address of LoadLibraryA in IAT... 006F5FE0
Injecting AnsiSupport.dll loader... OK
Saving... OK
Done.

I copied _cmd and the two DLLs to the system32 folder, and I made a symlink for the .mui file. It still doesn't work. Next, I'll try rebooting (in case that'll force it to reload the language or something; I don't understand the MUI concept well), and I'll report back with the results.
}
2010-03-30 18:36:25 = Daniel
{
Unfortunately, it didn't help. I'll follow this page for updates, but until then I'll look for other solutions. I'd love to get this to work, preferably for the whole console instead of just for cmd.

Sorry if this is a repeat post; I'm sure I sent this before, but I can't find it in the comments list now.
}
2010-08-19 21:56:43 = RichF
{
I have the same problem as Daniel. Has a solution been found? I am willing to do some testing. . . (I'll check back in a day or so. . . )
}
2010-08-19 22:02:33 = RichF
{
Interesting point. I noticed that the file size of _Cmd.exe is 305,664 while the original is 344,576. I would think that would be the other way around?
}
2010-08-22 01:22:48 = Gynvael Coldwind
{
@Daniel
Hmm, I'll look into the MUI issue. Anyway, I've overwritten the original cmd.exe, and never had an issue with languages before (to overwrite it, I removed cmd.exe from the dllcache directory, and changed cmd.exe owner to my user, and denied access to write cmd.exe for system and trusted installer, then overwritten it; this way it won't restore cmd.exe from a backup or sth).

As for the prompt:
set prompt=$e[m$e[t$p$e[T$e[1;31m$t$h$h$h $e[1;34m%USERNAME% $e[0;32m$g$e[1;32m

@RichF
Hmm, that is strange.

Also, please remember that this patch is for the 32-bit version of cmd.exe, so it will not work on the 64-bit version. I'll probably will make a 64-bit version in the future, but not sure when, sorry :)
}
2011-10-08 17:35:17 = zucchi
{
Hello,

Can you add define key functionality?
Define Key {ESC}[<key code>;<result>p

examples:
{ESC}[126;92p -- Redefine the tilde <~> key as a backslash <\>.
{ESC}[0;112;"dir|sort";13p -- Redefine <Alt><F9> as a Directory command piped to a Sort command, followed by a Carriage Return.
}
2012-08-28 07:15:14 = Vincent
{
Hi !

Windows 8 RTM failed.

Would you please update your code ??

Thank you.
Vincent
}
2012-10-15 23:45:34 = mkanet
{
There is still a need for a 64bit version for Win7. Is there any way to do this anywhere on the Internet?
}
2013-01-14 23:10:37 = aquishix
{
------------------
Message : Infected File Found!

Date and Time : 1/14/2013 4:03:29 PM
Name : C:\misc\dl\cmd_ansihack_004c\cmd_004c\_cmd.exe
Detected As : Artemis!7A68A451DAA4
State : Deleted
------------------

How disappointing...

Is this a false positive, or what? I really, really wanted to use this hack.

aquishix@gmail.com
}
2013-01-14 23:50:10 = Gynvael Coldwind
{
@aquishix
TL;DR: false positive or you already have a virus infection on your machine; there is a new version of this hack (link at the bottom)

Long version:
Yes, generally antivirus are disappointing, they tend to make you less secure, not detect all of malware (creating a false sense of security) and throw false positives at random stuff just because "it had a matching signature" (even if the signature is something commonly found in any software). I guess both "Sophail" papers provide a good illustration for that.
Not sure why people keep relying on these.

That said, I did mention in the above post that, the method will trigger an alarm in antivirus which rely on naive heuristics:
"6. It copies a short code to the last section - the code will load the AnsiSupport.dll library. It also changes the EP to the appended code (after the code loads the library, it jumps to OEP - some AV software might not be to happy about it, but who cares, just turn on the ignore on this file)"

Finally, if you don't trust the binary (which is actually a quite reasonable approach), you can either review it or the code that I did provide in the package. Using the reviewed code instead of the binary is always a safer choice.

Btw, there is a newer version of this hack (004d) - just go here: http://gynvael.coldwind.pl/?id=182

Cheers,
}
2013-04-04 11:52:02 = frank
{
Thank a lot for the ANSI hack (004d) ! It works really fine on my W7x64.
One remark indeed : When I run "_cmd.exe", all texts are in English (command help, etc.).
I would really appreciate keeping the native (French) interface language. How can this language issue be fixed ?

}
2013-11-16 00:53:48 = Arsen
{
Hi,

Is there any way to check in a *.bat file, if it was ran using the patched or orginal cmd.exe (and therefore if the ASCII escape codes are supported)?
}
2014-05-15 23:24:27 = FoxBMS
{
Hi there Gynvael,
great work, i looked for this looong time...
I'm using Win 7 x64 and Total Commander. I ran ansihack from console... got _cmd.exe backed up and rewrote original cmd, also copied ansisupport and dllspoof to system32, denied write rights to system and trustedinstaller, but it doesn't seems there is effort to restore original cmd from windows..... but it's ok, it's not my problem.

When i run new rewritten cmd.exe from totalcmd from any directory it working fine. Nice colored prompt and logo.
But what i'm doing wrong when i type cmd to windows run box (WIN + R), there appears one color (white) cmd window with escape color codes. ?? Where is the mistake ? THX for any advice.

p.s. Also registry method with Debugger value doesn't work for me, run box says it doesn't exist , type it again....
}
2014-05-15 23:28:00 = FoxBMS
{
Summarized, from explorer doesn't work, from totalcmd woks fine. ??
}
2014-05-15 23:47:32 = Gynvael Coldwind
{
@FoxBMS
My guess that you are using 32-bit Total Commander on a 64-bit system. Therefore when you run cmd.exe from TC, you run the 32-bit version, but Explorer runs the 64-bit one.

A quick fix would be to remove the 64-bit version, or change paths so that the 32-bit one is prefered (so PATH should point first to c:\windows\syswow64 and later to c:\windows\system32).

That said, please note that I'm no longer working on Ansi hack - some time ago I discovered conemu, which is a PuTTY-engine based console for Windows, which works really great, support ANSI colors and has quite a lot of other cool features, so... Ansi hack became not needed anymore ;)
}
2014-05-16 15:28:58 = FoxBMS
{
Thanks Gynvael,
you are right....
i restored original cmd to system32 and only set debugger value path to registry to new _cmd created from ansihack and works fine even from run box and explorer. No need for edit PATH variable. Beginner's mistake :)
I'll try conemu... i'll let you know .... THX for reply!
}
2014-05-17 19:39:12 = FoxBMS
{
So i grabbed conemu and tryin'...that's cool tip but can't find anywhere how to colorize prompt or output of dir command ? There's nothing in settings about this... :(
}

Add a comment:

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