Skip to main content

How to Decode Hexadecimal Text Back to ASCII in Batch Script

Decoding hexadecimal strings into readable ASCII text is a useful skill for anyone working with low-level data, scripting, or security analysis. If you’ve ever encountered a sequence like 48 65 6C 6C 6F and wanted to turn it back into Hello using nothing but the Windows Command Prompt, you’re in the right place.

This guide walks you through how to perform that conversion entirely in Batch Script, no external tools, no additional languages required. Whether you’re analyzing encoded data, exploring how obfuscation works, or pushing the limits of what CMD can do, you’ll learn a practical method based on variable mapping and string parsing to translate hexadecimal values into plain text efficiently.

The Principle of Hex to ASCII Conversion

In a Windows command environment, standard printable characters map directly to numerical values. For example, the string "A" is mapped to 41 in Hexadecimal.

Unfortunately, Batch possesses no built-in decode_hex() library function. To achieve the conversion natively, we must build a reverse-lookup dictionary where the key (the variable name) is the Hexadecimal pair, and the value stored inside that variable is the corresponding plain character.

Creating the Reverse Lookup Array

The foundational step to any robust script is defining the ruleset. We generate our mapping list where each variable is prefixed (e.g., hex_) followed by the specific two-character hexadecimal value.

@echo off
setlocal enabledelayedexpansion
title Hex to ASCII Decoder

:: Manually mapping common Hex to ASCII Characters
set "hex_41=A"
set "hex_42=B"
set "hex_43=C"
set "hex_44=D"
set "hex_45=E"
set "hex_46=F"

set "hex_61=a"
set "hex_62=b"
set "hex_63=c"

set "hex_30=0"
set "hex_31=1"
set "hex_32=2"
set "hex_2E=."
warning

Variables must be created deliberately. If the script attempts to decode a Hexadecimal value (like 0A for Line Feed) that you have not defined in the lookup dictionary, the script will return empty variables unless a fallback logic is provided!

Implementing the Processing Loop

After the dictionary array is loaded into memory, the program must accept an input string (like 41 42 43), slice it into two-character pairs, and request the decoded equivalent from our array.

Looping Through Hex Pairs

Strings encoded in hex usually have two characters per byte, frequently separated by spaces. If they do not have spaces (e.g., 414243), our script must step exactly two indexes forward at a time. The safest logic involves parsing the string, extracting two characters using slicing syntax, and looking up each pair in the dictionary.

set "HEX_INPUT="
set /p "HEX_INPUT=Enter Hex sequence (no spaces): "
set "ASCII_OUTPUT="
set "ptr=0"

:DECODE_LOOP
:: Extract two characters based on 'ptr' starting point
set "hex_pair=!HEX_INPUT:~%ptr%,2!"

:: If the extraction results in nothing, we've hit the end of the string
if "!hex_pair!"=="" goto DISPLAY_ASCII

:: Get the decoded character from the map
set "char=!hex_%hex_pair%!"

:: Handle undefined pairs
if not defined char (
set "char=?"
)

:: Append the retrieved character to our final output
set "ASCII_OUTPUT=!ASCII_OUTPUT!!char!"

:: Increment the pointer by 2 (since hex uses two digits per char)
set /a ptr+=2
goto DECODE_LOOP

Common Wrong Cases and Best Practices

A classic stumbling block when manipulating special command characters (&, |, >) natively as variables is accidentally executing them. Command Prompt logic treats special characters as commands unless properly quoted.

The Wrong Way: Assigning Poison Characters Directly

When creating your lookup dictionary, if you attempt to assign an unquoted logical operator to a variable, Batch evaluates it immediately.

Wrong Code Example:

:: Attempting to map Hex 26 (Ampersand &) and 3E (Greater Than >)
set hex_26=&
set hex_3E=>

What Happens: CMD parses set hex_26= and then stops. It views the & symbol as "Execute the next command on this line". Because there is nothing after the &, the variable receives an empty string, or worse, crashes the script entirely if there was unexpected trailing text. The same applies for >, which CMD thinks is a redirection command, leading it to create random empty files on the desktop.

The Correct Way: Strictly Defined Double Quotes

To securely define poison characters in your batch memory so your script can decode them when requested, you must wrap the entire assignment equation inside double quotation marks. The setlocal enabledelayedexpansion command then allows you to seamlessly construct the final output.

Correct Code Example:

@echo off
setlocal enabledelayedexpansion

:: Notice the quotation marks wrap the variable name AND the poison value
set "hex_26=&"
set "hex_3E=>"
set "hex_7C=|"

What Happens: The Command Prompt perfectly captures & and assigns it to hex_26 exactly as a plain text string instead of a command processor instruction. The script remains stable.

Full Script Implementation

Putting the dictionary array generation, spatial variable assignments, and the two-step jump loop together produces an effective, completely portable Hex decoding tool natively built into Windows. Save the following code as hexdecode.bat and execute it!

@echo off
setlocal enabledelayedexpansion
title Native Hex to ASCII Decoder

echo Loading Hex Dictionary...
:: 1. Building the Reverse Hex Map
set "hex_41=A" & set "hex_42=B" & set "hex_43=C" & set "hex_44=D"
set "hex_45=E" & set "hex_46=F" & set "hex_47=G" & set "hex_48=H"
set "hex_49=I" & set "hex_4A=J" & set "hex_4B=K" & set "hex_4C=L"
set "hex_4D=M" & set "hex_4E=N" & set "hex_4F=O" & set "hex_50=P"
set "hex_51=Q" & set "hex_52=R" & set "hex_53=S" & set "hex_54=T"
set "hex_55=U" & set "hex_56=V" & set "hex_57=W" & set "hex_58=X"
set "hex_59=Y" & set "hex_5A=Z"

set "hex_61=a" & set "hex_62=b" & set "hex_63=c" & set "hex_64=d"
set "hex_65=e" & set "hex_66=f" & set "hex_67=g" & set "hex_68=h"
set "hex_69=i" & set "hex_6A=j" & set "hex_6B=k" & set "hex_6C=l"
set "hex_6D=m" & set "hex_6E=n" & set "hex_6F=o" & set "hex_70=p"
set "hex_71=q" & set "hex_72=r" & set "hex_73=s" & set "hex_74=t"
set "hex_75=u" & set "hex_76=v" & set "hex_77=w" & set "hex_78=x"
set "hex_79=y" & set "hex_7A=z"

set "hex_30=0" & set "hex_31=1" & set "hex_32=2" & set "hex_33=3"
set "hex_34=4" & set "hex_35=5" & set "hex_36=6" & set "hex_37=7"
set "hex_38=8" & set "hex_39=9"

:: Handling spacing and special characters
set "hex_20= "
set "hex_26=&"
set "hex_7C=|"
set "hex_3C=<"
set "hex_3E=>"
set "hex_2E=."
set "hex_2C=,"
set "hex_3F=?"
set "hex_2D=-"
set "hex_5F=_"
set "hex_3A=:"
set "hex_3B=;"
set "hex_27='"
set "hex_40=@"
set "hex_23=#"
set "hex_24=$"
set "hex_25=%%"
set "hex_2B=+"
set "hex_3D=="
set "hex_7E=~"
set "hex_28=("
set "hex_29=)"
set "hex_5B=["
set "hex_5D=]"
set "hex_7B={"
set "hex_7D=}"
set "hex_2F=/"
set "hex_5C=\"
set "hex_21=^!"
set "hex_22=""
set "hex_5E=^^"

:PROMPT
cls
echo =========================================
echo HEX TO ASCII DECODER CONSOLE
echo =========================================
echo Example: 48656C6C6F
echo.
set "HEX_INPUT="
set /p "HEX_INPUT=Enter Hex sequence linearly (No Spaces): "

if not defined HEX_INPUT goto PROMPT

:: 2. Initialize the loop parameters
set "ASCII_OUTPUT="
set "ptr=0"

:LOOP
:: 3. Grab two characters at a time using a FOR trick to resolve ptr
for %%P in (!ptr!) do set "hex_pair=!HEX_INPUT:~%%P,2!"
if "!hex_pair!"=="" goto END_LOOP

:: Format check - if someone types an odd number of characters, the last grab might be 1 character
set "second_digit=!hex_pair:~1,1!"
if "!second_digit!"=="" (
set "ASCII_OUTPUT=!ASCII_OUTPUT![Incomplete Hex Block]"
goto END_LOOP
)

:: 4. Look up translation in dictionary using a FOR trick to resolve the pair
for %%H in (!hex_pair!) do set "char=!hex_%%H!"

:: 5. Fallback for unrecognized/undefined hex blocks
if not defined char (
set "char=[0x!hex_pair!]"
)

:: 6. Piece the output together
set "ASCII_OUTPUT=!ASCII_OUTPUT!!char!"

:: Reset char for the next iteration
set "char="

:: Increment the pointer by 2 to grab the next pair
set /a ptr+=2
goto LOOP

:END_LOOP
echo.
echo Original Hex Input:
echo !HEX_INPUT!
echo.
echo Decoded Output:
echo !ASCII_OUTPUT!
echo.
pause
goto PROMPT
info

By utilizing the delayed expansion characters (!ASCII_OUTPUT!) during the echo commands instead of percentage signs (%), the final decoded string will perfectly print any correctly retrieved poison characters (e.g., & or |) seamlessly without evaluating them at runtime.

Conclusion

Developing an active string manipulation decoder in Windows Batch Scripting confirms an expert level understanding of array handling, nested extraction mechanisms, and delayed expansion security features. While you must laboriously populate the dictionary for special characters manually, constructing an in-memory two-step hexadecimal mapping algorithm ensures your script remains completely independent from third party software logic modules, ready to immediately resolve obfuscated binary structures natively inside the command terminal.