here - Chris Ferguson

advertisement
Task Overview
I was provided with a skeletal program written in C++ and assembler to work with. The program
allowed the user to type in a number of alphanumeric characters which were then ‘encrypted’ by
being converted, to another value, with both the original and encrypted character strings being
echoed to the screen. I was allocated an encryption method, written in x86 assembler code, that I
pasted into the skeletal program, replacing the encryption method present. This encryption routine
also employed an encryption key that had to be inputted when asked for it.
I was given four tasks to do and these were as follows:




Task One - Understand & comment the Encryption code
Task Two - Implement the stdcall/cdecl subroutine call convention
Task Three - Implement the Decryption routine
Task Four - Convert the encrypt_chars subroutine into ASM and convert the decrypted string
into lowercase
The encryption key I used was "p" and the string I used was "Amaze" (correct case).
Screenshot of Working Program
Below is the screenshot of the working program using encryption code "p" and source string
"Amaze". The program encrypts the source string and then decrypts it all in lower case.
Tasks One, Two and Three
The source code on the following page contains sufficient meaningful comments which I have added
to the source code to demonstrate my understanding and has been altered so that it adopts the
accepted C++ standard calling procedure for passing parameters into the encrypt and decrypt
subroutines (cdecl). This uses the stack and the EBP register rather than the general purpose
registers that were used in the original program. A decrypt_chars subroutine has also been added,
written in C++ and assembler, similar to the encrypt_chars routine, which reverses the encryption.
The assembly code produced is fully commented and uses the same cdecl mechanism employed in
the encryption subroutine.
Name: Christopher Ferguson
Student Number: 20128874
FoCA Assignment 2
Encryption Program Source Code with Tasks One, Two and Three Implemented
// The encryption program in C++ and ASM using encryption method 22 provided to me.
// Filename: "4473 FoCA 2012 Encryption Assignment.cpp"
// Christopher Ferguson, last update: March 2012
#include <conio.h>
#include <iostream>
using namespace std;
#define MAXCHARS 5
#define dollarchar '$'
//for kbhit
//for cin >> and cout <<
// feel free to alter this, but 5 is the minimum
// string terminator
char OChars[MAXCHARS], EChars[MAXCHARS], DChars[MAXCHARS];
// Global Original, Encrypted, Decrypted character strings
//----------------------------- C++ Functions ---------------------------------------------------------void get_char (char& a_character)
{
cin >> a_character;
while (((a_character < '0') | (a_character > 'z')) && (a_character != dollarchar))
{
cout << "Alphanumeric characters only, please try again > ";
cin >> a_character;
}
}
//------------------------------------------------------------------------------------------------------------void get_original_chars (int& length)
{
char next_char;
length = 0;
get_char (next_char);
while ((length < MAXCHARS) && (next_char != dollarchar))
{
OChars [length++] = next_char;
get_char (next_char);
Name: Christopher Ferguson
Student Number: 20128874
FoCA Assignment 2
}
}
//------------------------------------------------------------------------------------------------------------void show_string (char a_string[], int length)
{
for (int i=0; i<length; i++)
cout << a_string [i];
cout << "\n\n";
}
//----------------- ENCRYPTION ROUTINES ------------------------------------------------------------------------void encrypt_chars (int length, char EKey)
{
char temp_char;
for (int i = 0; i < length; i++){
temp_char = OChars [i];
__asm {
push
eax
push
ecx
// original/encrypted char temporary store
//get next char from original string
; call the encrypt subroutine
; save register values on stack to be safe
push temp_char
push EKey
;push character to stack
;push encryption key to stack
call
; encrypt the character (call encrypt function)
encrypt22
add esp, 8
;tidy up the stack. Add 4 for each parameter push. 2 parameters so 4.
mov
pop
pop
; only need low byte of EAX to return encrypted char
; restore original register values from stack
temp_char,al
ecx
eax
}
EChars [i] = temp_char;
// Store encrypted char in the encrypted chars array
}
return;
// ---------------------------- start of ASM code --------------------------------------------------------------__asm {
// Encrypt subroutine.
Name: Christopher Ferguson
Student Number: 20128874
FoCA Assignment 2
// Inputs: register EAX = Encryption Key value, and ECX = the character to be encrypted. (via CDECL)
// Outputs: register EAX = the encrypted value of the source character.
encrypt22:
push ebp
mov ebp, esp
;push the EBP register on the stack to save its present value
;copy the ESP value into the EBP - this is its new fixed value.
xor
eax,eax
xor
ecx,ecx
mov eax, [ebp+8]
mov ecx, [ebp+12]
;clear registers to 0 so that values can be popped in
push edx
ror cl,1
ror cl,1
ror cl,1
ror cl,1
;push edx to the
;Rotate right by
;Rotate right by
;Rotate right by
;Rotate right by
;pop encryption key from stack
;pop character from stack
stack
1 bit
(8 bit register in ECX)
1 bit
(8 bit register in ECX)
1 bit
(8 bit register in ECX)
1 bit (8 bit register in ECX)
//rotates cl by 4 bits (8 bit register in ECX, where character to be encrypted is stored)
push ecx
;push ECX to the stack
add eax,0x55
;add 0x55 (85 in decimal) (0101 0101 in binary) to EAX
//EAX contains encryption key. hex value of p = 0x70 (0111 0000 in binary)
//EAX now equal to 0xF5 (245 in decimal) (1111 0101 in binary)
mov edx,eax
;move EAX into EDX
//EAX value moved into EDX. EDX now equal to 0xF5 (245 in decimal) (1111 0101 in binary)
pop eax
;pop ECX into EAX
//value to be encrypted now in EAX
xor eax,edx
;XOR EAX with EDX
//XORs value to be encrypted with encryption key
Name: Christopher Ferguson
Student Number: 20128874
FoCA Assignment 2
ror al,1
ror al,1
;Rotate right by 1 bit (8 bit register in EAX)
;Rotate right by 1 bit (8 bit register in EAX)
//rotated by 2 bits
not al
add eax,0x10
pop edx
;all set bits cleared and all cleared bits set. (8 bit register in EAX)
;add 0x10 (16) to EAX
;restore EDX to previous state
pop ebp
;pop the original value of EBP back into EBP from the stack.
ret
;return from subroutine
}
//----------------------------- End of ASM code ----------------------------------------------------------------} // end of encrypt_chars function
//----------------- DECRYPTION ROUTINES ------------------------------------------------------------------------void decrypt_chars (int length, char EKey)
{
char temp_char;
for (int i = 0; i < length; i++){
temp_char = EChars [i];
__asm {
push
eax
push
edx
//original/encrypted char temporary store
//get next char from original string
;save register values on stack to be safe
push temp_char
push EKey
;pass the source character using cdecl
;and encryption key.
call
;encrypt the character
decrypt
add esp, 8
;tidy up the stack. Add 4 for each parameter push. 2 parameters so 4.
mov
pop
pop
;only need low byte of EAX to return decrypted char
;restore original register values from stack
Name: Christopher Ferguson
temp_char,al
edx
eax
Student Number: 20128874
FoCA Assignment 2
}
DChars [i] = temp_char;
//Store encrypted char in the encrypted chars array
}
return;
// ---------------------------- start of ASM code --------------------------------------------------------------__asm {
// Decrypt subroutine.
// Inputs: register EDX = Encryption Key value, and EAX = the character to be decrypted. (via CDECL)
// Outputs: register EAX = the encrypted value of the source character.
decrypt:
push ebp
mov ebp, esp
;push the EBP register on the stack to save its present value
;copy the ESP value into the EBP - this is its new fixed value.
xor
eax,eax
xor
ecx,ecx
mov edx, [ebp+8]
mov eax, [ebp+12]
;clear registers to 0 so that values can be popped in
add
sub
not
rol
xor
rol
;add 55h (85) to EDX (encryption key)
;subtract 10h (16) from EAX (encrypted character)
;all set bits cleared and all cleared bits set. (8 bit register in EAX)
;Rotate left by 1 bit (8 bit register in EAX)
;XOR EAX with EDX (encrypted character with encryption key)
;Rotate left by 1 bit (8 bit register in EAX)
edx, 0x55
eax, 0x10
al
al,2
eax,edx
al, 4
;retrieve encryption key from stack
;retrieve character from stack
pop ebp
;pop back EBP from the stack
ret
;return from subroutine
}
//----------------------------- End of ASM code ----------------------------------------------------------------} // end of encrypt_chars function
//----------------------------- End of C++ Functions -------------------------------------------------------------
Name: Christopher Ferguson
Student Number: 20128874
FoCA Assignment 2
int main(void)
{
int char_count;
char EKey;
// The number of actual characters entered (upto MAXCHARS limit)
// Encryption key,
cout << "\nPlease enter your Encryption Key (EKey) letter: ";
get_char (EKey);
cout << "\nNow enter upto " << MAXCHARS << " alphanumeric characters:\n\n";
get_original_chars (char_count);
cout << "Original source string = ";
show_string (OChars, char_count);
encrypt_chars (char_count, EKey);
cout << "Encrypted string =
";
show_string (EChars, char_count);
// encrypts string
decrypt_chars (char_count, EKey);
cout << "Decrypted string =
";
show_string (DChars, char_count);
// decrypts string
cout << "Press a key to end...";
while ( !_kbhit());
return (0);
//hold the screen until a key is pressed
} // end of whole encryption/decryption program --------------------------------------------------------------------
Name: Christopher Ferguson
Student Number: 20128874
FoCA Assignment 2
Task 4
I have, to the best of my ability, converted the body of the encrypt_chars and decrypt_chars
functions to assembler code. This includes the usage of the OChars, EChars and DChars arrays all in
assembler language. The encryption and decryption routines have all been optimised by minimising
the use of registers and instructions to make the code smaller faster, removing all redundant code
and inlining the functions. All commenting code has been updated to match these changes.
Once this was completed I implemented task five so that any string entered in any case will be
automatically decrypted in lower case. This is done by ORing the register containing the decrypted
character with 20h (32 in decimal and 100000 in binary) which will convert an upper case character
to lower case without affecting any other characters. This works as the bit 5 needs to be changed
from a zero to a one so this number ORed with any character will convert it to it's lower case
standard or not affect it if it is already lower case or not a character that needs to be converted to
lower case (i.e. a number).
Name: Christopher Ferguson
Student Number: 20128874
FoCA Assignment 2
Encryption and Decryption Routines with Task Four Implemented
//----------------- ENCRYPTION ROUTINE ------------------------------------------------------------------------void encrypt_chars (int length, char EKey)
{
int i;
//index used for manipulating the array
__asm {
encryptionloop:
checkend:
mov
jmp
mov
inc
mov
i,0
checkend
eax, i
eax
i, eax
cmp i, 5
jge endencryption
add
xor
ror
not
add
;for loop in assembler
;5 is the length of string
;jump if index greater or equal then 5
mov edx,i
;move index into EDX
push
push
; save register values on stack to be safe
eax
ecx
movsx ecx,[edx+OChars]
; enregister the source character
movsx
; and encryption key.
eax,EKey
// encrypt the character
ror cl,4
eax,0x55
ecx,eax
cl,2
cl
ecx,0x10
//character encrypted
mov
Name: Christopher Ferguson
[edx+EChars],cl
Student Number: 20128874
;Rotate right by 4 bits (8 bit register in ECX)
;add 0x55 (85 in decimal) (0101 0101 in binary) to EAX
;XOR EAX with EDX
;Rotate right by 2 bits (8 bit register in ECX)
;all set bits cleared and all cleared bits set. (8 bit register in ECX)
;add 0x10 (16) to ECX
; store encrypted character in encrypted character array
FoCA Assignment 2
pop
pop
ecx
eax
; restore original register values from stack
jmp encryptionloop
endencryption:
}
return;
} // end of encrypt_chars function
//----------------- DECRYPTION ROUTINE ------------------------------------------------------------------------void decrypt_chars (int length, char EKey)
{
int i;
__asm {
decryptionloop:
checkend:
mov
jmp
mov
inc
mov
i,0
checkend
eax, i
eax
i, eax
cmp i, 5
jge enddecryption
push
push
eax
ecx
;set index variable to 1
;for loop in assembler, move index into EAX
;increment i for manipulation the array
;5 is the length of string
;jump if index greater or equal then 5
; save register values on stack to be safe
mov ecx,i
;move index into EAX
movsx
movsx
; enregister the source character
; and encryption key.
eax,[ecx+EChars]
edx,EKey
//decryption sequence
add edx, 0x55
sub eax, 0x10
Name: Christopher Ferguson
Student Number: 20128874
;sets EDX to value it was before register was popped
;subtracts 0x10 (16) from EAX
FoCA Assignment 2
not
rol
xor
rol
al
al,2
eax,edx
al, 4
;all set bits cleared and all cleared bits set. (8 bit register in EAX)
;Rotate left by 2 bits (8 bit register in EAX)
;xors eax with edx
;Rotate left by 4 bits (8 bit register in EAX)
//character decrypted
or
eax,20h
;convert to lower case
mov
pop
pop
[ecx+DChars],al
ecx
eax
; only need low byte of EAX to return decrypted char
; restore original register values from stack
jmp decryptionloop
enddecryption:
}
return;
} // end of decrypt_chars function
Name: Christopher Ferguson
Student Number: 20128874
FoCA Assignment 2
Download