.NET Zone is brought to you in partnership with:

Den is a DZone Zone Leader and has posted 460 posts at DZone. You can read more from them at their website. View Full User Profile

Let's Talk ASM - XOR-ing a String

05.10.2013
| 2203 views |
  • submit to reddit

I remember the first time I started programming, I wanted to find a way to encrypt a string in some way. I managed to accomplish that in Visual Basic 6 with the help of the standard XOR. Obviously, this is not even in the same area code with proper encryption - it is merely a character swap and you should never, under any circumstances, use this in production. Ever. For training purposes, however, let's see how this can be done in x86 Assembly.

Once again, make sure that you download the proper solutions that you can test with. This is not mandatory, but makes the process much easier when it comes to receiving user input and displaying the output.

Let's begin with the standard declarations - we need to include the containers for both the "encrypted" and "decrypted" strings:
.586
.MODEL FLAT

INCLUDE io.h            ; header file for input/output

.STACK 4096

.DATA
	INPUTPROMPT BYTE "String to encrypt:", 0
	OUTPUTPROMPT BYTE "Data", 0

	TARGETSTRING BYTE 50 DUP(0), 0
	DECRYPTEDSTRING BYTE 50 DUP(0), 0
	ENCRYPTEDSTRING BYTE 50 DUP(0), 0
To make it easier to manipulate data, I've split the program itself in two procedures:

  • GetText
  • EncryptText
GetText is merely a wrapper for the standard input call:
GetText PROC
	input INPUTPROMPT, TARGETSTRING, 40
	lea EDI, [TARGETSTRING]

	ret
GetText ENDP
Once the string is obtained, its address is moved in the EDI register, after which the program flow continues from the next step - obtaining the length of the input string:
sub			ECX, ECX
sub			AL, AL
not			ECX
cld
repne		scasb
not			ECX
dec			ECX
add			EDX, ECX

push ECX
The returned length is pushed onto the stack, and we can now "encrypt" the string:
EncryptText PROC
	lea EDX, [TARGETSTRING]
	lea EBX, [ENCRYPTEDSTRING]
	
	ENC_LOOP:
		mov EAX, [EDX] 
		xor EAX, 2
		mov [EBX], EAX 
		inc EDX
		inc EBX
	LOOP ENC_LOOP

	output OUTPUTPROMPT, ENCRYPTEDSTRING
	ret
EncryptText ENDP
Assuming that this program has the sole purpose of swapping characters in a given string, there is no inherent need to push the contents of EDX and EBX onto the stack when the procedure is invoked. For any other scenarios, you might want to preserve those values to protect necessary data from being accidentally overriden.The LOOP sub-routine is executed n-times, where n is the length of the string stored in ECX. The ECX register will be decremented automatically for each iteration, but since we have the input string stored in EDX, I need to increment that register, and subsequently - EBX, where the modified string is stored, in order to maintain a 1-to-1 character binding.The value passed to the XOR call can also be obtained from the stack, if desired. The reverse operation is absolutely identical, due to the nature of XOR itself.



For your convenience here is the entire program:

.586
.MODEL FLAT

INCLUDE io.h            ; header file for input/output

.STACK 4096

.DATA
	INPUTPROMPT BYTE "String to encrypt:", 0
	OUTPUTPROMPT BYTE "Data", 0

	TARGETSTRING BYTE 50 DUP(0), 0
	DECRYPTEDSTRING BYTE 50 DUP(0), 0
	ENCRYPTEDSTRING BYTE 50 DUP(0), 0

.CODE
_MainProc PROC
	call GetText
	
	sub			ECX, ECX
	sub			AL, AL
	not			ECX
	cld
	repne		scasb
	not			ECX
	dec			ECX
	add			EDX, ECX

	push ECX

	call EncryptText

	pop ECX

	call DecryptText
	
	mov EAX, 0
	ret
_MainProc ENDP

GetText PROC
	input INPUTPROMPT, TARGETSTRING, 40
	lea EDI, [TARGETSTRING]

	ret
GetText ENDP

EncryptText PROC
	lea EDX, [TARGETSTRING]
	lea EBX, [ENCRYPTEDSTRING]
	
	ENC_LOOP:
		mov EAX, [EDX] 
		xor EAX, 2
		mov [EBX], EAX 
		inc EDX
		inc EBX
	LOOP ENC_LOOP

	output OUTPUTPROMPT, ENCRYPTEDSTRING
	ret
EncryptText ENDP
			END