Echo Unreadable Hex Characters in Windows: forfiles
How to transfer small files to a locked-down Windows machine? When there is no option to copy, ftp, or http GET a file. When powershell is blocked so that you can only use Windows cmd commands?
My first choice would be to use certutil: certutil is a built-in tool for certificate and PKI management. It can encode binary certificate files - resulting in the familiar PEM output, starting with "----BEGIN CERTIFICATE-----". But it can actually encode any binary file! So you can 'convert' an executable to a certificate encoded in readable characters, and copy the fake PEM certificate by echo-ing out each of its lines on the target machine. Then the original exectutable is recovered by decoding the file again with certutil.
But what if certutil is also blocked, and you need to write / paste unreadable characters?
On Linux, you could run
echo -e "\x41" A
But Windows echo does not have an option to translate characters encoded in hex automatically.
The command line tool forfiles allows to do this, albeit in a bit convoluted way:
forfiles processes files in a directory, interprets the files' metadata. The examples in the help information give an overview about what the tool is typically used for:
forfiles /? FORFILES /P C:\WINDOWS /S /M DNS*.* FORFILES /S /M *.txt /C "cmd /c type @file | more" FORFILES /P C:\ /S /M *.bat FORFILES /D -30 /M *.exe /C "cmd /c echo @path 0x09 was changed 30 days ago" FORFILES /D 01.01.2001 /C "cmd /c echo @fname is new since Jan 1st 2001" FORFILES /D +8.5.2019 /C "cmd /c echo @fname is new today" FORFILES /M *.exe /D +1 FORFILES /S /M *.doc /C "cmd /c echo @fsize" FORFILES /M *.txt /C "cmd /c if @isdir==FALSE notepad.exe @file"
For each file in a filtered set a command can be executed with option /C. The interesting example is the one referring to
echo @path 0x09
The help explains:
To include special characters in the command line, use the hexadecimal code for the character in 0xHH format (ex. 0x09 for tab). Internal CMD.exe commands should be preceded with "cmd /c".
You want to run a single command, so you need to run forfiles once. Thus create an empty directory, cd to it, and create a single dummy file within it:
C:\test>echo test >test.txt
Then run echo [hex string] for that single file, like this. It outputs the interpreted characters corresponding to the hexadecimal values:
C:\test>forfiles /c "cmd /c echo 0x410x420x430x01" ABC☺ C:\test>
Remaining issue: Newlines are added before and after the string. Especially the one at the beginning could be problematic if the operating system would try to find the magic bytes for a certain type of file there.
The first newline is removed by redirecting echo within the enclosed command (whereas redirecting the whole forfiles command would keep it)
C:\test>forfiles /c "cmd /c echo 0x410x420x430x01 >out.txt" C:\test>type out.txt ABC☺ C:\test>
The trailing extra line is a superfluous carriage return + linefeed. It can be removed by using the set command in this way:
This sets a variable without specifying a variable name, so the error level is set to 1. Nevertheless, it outputs the value of this non-existing variable - without an appended line break.
C:\test>forfiles /c "cmd /c set /p=0x410x420x430x01 >out.txt" C:\test>type out.txt ABC☺
This command seems to 'hang' and you need to ENTER once more to complete it. cmd is waiting for input here, and you can add input from the nul device - then the command is completed in one step:
C:\test>forfiles /c "cmd /c <nul set /p=0x410x420x430x01 >out.txt"
But there is still one a blank character (Hex 32) appended at the end:
C:\test>powershell Get-Content out.txt -encoding Byte 65 66 67 1 32
This blank goes away if no blank is entered between the hex string and the >:
C:\test>forfiles /c "cmd /c <nul set /p=0x410x420x430x01>out.txt" C:\test>powershell Get-Content out.txt -encoding Byte 65 66 67 1
Remaining limitation: The contents of the variable must not begin with special characters that will trip up the set command. E.g. an equal sign at the beginning is a bad character (and it does not matter if this character is hex-encoded or not).