user12398810
user12398810

Reputation:

x86 assembly encryption to decryption

So I am trying to create decryption from an encryption routine but I really have a poor experience with it. Can anyone please help me? Thank you in advance!

PS. the routine is poorly written intentionally for us to change later on. edited: sorry, here is my whole encry[ption routine, all I know is that everything done with my EKey (eax) should remain the same but I need to reverse whats done with the char (ecx). I dont really know where to start, Thanks in advance again.

char EKey = 'z';      //unique key:z

#define StudentName "asdasd"
#define MAXCHARS 6    // Max user input

using namespace std;
#include <string>               // for strings
#include <fstream>              // file I/O
#include <iostream>             // for cin >> and cout <<
#include <iomanip>              // for fancy output
#include "TimeUtils.h"          // for GetTime, GetDate, etc.

#define dollarchar '$'          // string terminator

char OChars[MAXCHARS] = { 'S','O','S','I','G',' ' },     // Original character string
EChars[MAXCHARS],                                        // Encrypted character string
DChars[MAXCHARS] = "Soon!";                              // Decrypted character string

//----------------------------- C++ Functions ----------------------------------------------------------

void get_char(char& a_character)
{
    a_character = (char)_getwche();
    if (a_character == '\r' || a_character == '\n')  // allow the enter key to work as the terminating character too
        a_character = dollarchar;
}
//-------------------------------------------------------------------------------------------------------------

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);
    }
}

//----------------- ENCRYPTION ROUTINES -----------------//

void encrypt_chars(int length, char EKey)
{
    char temp_char;                             // Character temporary store

    for (int i = 0; i < length; i++)            // Encrypt characters one at a time
    {
        temp_char = OChars[i];                  // Get the next char from Original Chars array

        __asm
        {
            push   eax                          //saves EKey to the memory stack w/ a value of 0
            push   ecx                          //saves Char to the memory stack w/ a value of 83
            push   edx                          //saves EKey to the memory stack w/ a value of 1

            movzx  ecx, temp_char               //moves my character value (8 bit) to ecx (32 bit) w/ 0 extension which is 'S' and continues until the last character of my string. 

            lea    eax, EKey                    //lea (loads effective address) puts the memory address of EKey to eax 
            push   ecx                          //saves Char to the memory stack w/ a value of 83
            push   eax                          //saves Char to the memory stack w/ a value of 5241440

            call   encrypt_3                    //calls a function in this case my unique encryption routine  
            add    esp, 8                       //adds a value of 8 to the stack pointer, esp= 5241176 + 8 
            mov    temp_char, dl                //copies the value of the encrypted Char to the current Char

            pop    edx                          //removes the encrypted char from the stack memory 
            pop    ecx                          //removes the char from the stack memory   
            pop    eax                          //removes the  EKey from the stack memory
        }
        EChars[i] = temp_char;                  // Store encrypted char in the Encrypted Chars array
    }
    return;

    __asm
    {
    encrypt_3:
        push ebp                                //saves ebp to the stack memory
            mov ebp, esp                        //copies the value of esp to ebp
            mov eax, [ebp + 8]                  //adds 8 to the value of ebp then copy its value to EKey
            mov ecx, [ebp + 12]                 //adds 12 to the value of ebp (recently added 8) then copy the value to the encrypted character
            push  edx                           //puts the edx to the stack memory  
            push  ecx                           //puts CHAR to the stack memory
            push  eax                           //puts EKey to the stack memory
            movzx eax, byte ptr[eax]            //Uses the EKey (z) inside eax as the eax memory address 
            rol   al, 1                         //rotate al by 1 bit to the left, 111 1010‬ (moves the 0 at the end to the beginning)
            not al                              //invert each bit of al (1111 0100‬) becomes 0000 1011
            rol   al, 1                         //rotates the inverted binary of al to the left by 1 bit 
            rol   al, 1                         //rotates al binary by 1 bit again to the left, 0001 0110‬
            mov   edx, eax                      //copies the value of Ekey to edx, edx = 44
            pop   eax                           //removes the eax register from the stack memory        
            mov   byte ptr[eax], dl             //Uses the value of edx as the byte address of eax (Ekey)
            pop   ecx                           //removes the ecx (EKey) from the stack memory
            xor ecx, edx                        //implements the XOR operation between edx and CHAR, 83 and 44 becomes 127 (111 1111)
            mov   eax, ecx                      //copy the XORed value of Char to EKey
            ror   al, 1                         //rotates al value by 1 bit to the right 127 (0111 1111‬)
            ror   al, 1                         //rotates al value by 1 bit to the right 191 (1011 1111‬)
            ror   al, 1                         //rotates al value by 1 bit to the right 223 (1101 1111‬) al value is now 239 (1110 1111‬)
            pop   edx                           //removes edx from the stack memory 
            mov   edx, eax                      //copy the value of EKey to edx 239 (1110 1111‬)
            pop  ebp                            //removes ebp from the stack memory
            ret                                 //proceeds to the line after the call instruction 
    }
}

//----------------- DECRYPTION ROUTINES -----------------//

void decrypt_chars(int length, char EKey)
{
    char temp_char;                             // Character temporary store

    for (int i = 0; i < length; i++)            // Decrypt characters one at a time
    {
        temp_char = EChars[i];                  // Get the next char from Encrypted Chars array

        __asm
        {
            push   eax                          //saves EKey to the memory stack w/ a value of 0
            push   ecx                          //saves Char to the memory stack w/ a value of 83

            movzx  ecx, temp_char               //moves my character value (8 bit) to ecx (32 bit) w/ 0 extension which is 'S' and continues until the last character of my string. 

            lea    eax, EKey                    //lea (loads effective address) puts the memory address of EKey to eax 
            push   ecx                          //saves Char to the memory stack w/ a value of 83
            push   eax                          //saves Char to the memory stack w/ a value of 5241440

            call   decrypt_3                    //calls a function in this case my unique encryption routine  
            add    esp, 8                       //adds a value of 8 to the stack pointer, esp= 5241176 + 8 
            mov    temp_char, dl                //copies the value of the encrypted Char to the current Char

            pop    ecx                          //removes the char from the stack memory   
            pop    eax                          //removes the  EKey from the stack memory
        }
        DChars[i] = temp_char;                  // Store decrypted char in the decrypted Chars array
    }
    return;
    __asm
    {
    decrypt_3:
        push ebp                                //saves ebp to the stack memory
            mov   ebp, esp                      //copies the value of esp to ebp
            mov   eax, [ebp + 8]                //adds 8 to the value of ebp then copy its value to EKey
            mov   ecx, [ebp + 12]               //adds 12 to the value of ebp (recently added 8) then copy the value to the encrypted character

            push  edx                           //puts the edx to the stack memory  
            push  ecx                           //puts CHAR to the stack memory
            push  eax                           //puts EKey to the stack memory

            movzx eax, byte ptr[eax]            //Uses the EKey (z) inside eax as the eax memory address 
            rol   al, 1                         //rotate al by 1 bit to the left, 111 1010‬ (moves the 0 at the end to the beginning)
            not al                              //invert each bit of al (1111 0100‬) becomes 0000 1011
            rol   al, 1                         //rotates the inverted binary of al to the left by 1 bit 
            rol   al, 1                         //rotates al binary by 1 bit again to the left, 0001 0110‬
            mov   edx, eax                      //copies the value of Ekey to edx, edx = 44
            pop   eax                           //removes the eax register from the stack memory        
            mov   byte ptr[eax], dl             //Uses the value of edx as the byte address of eax (Ekey)
            pop   ecx                           //removes the ecx (EKey) from the stack memory
            xor ecx, edx                        //implements the XOR operation between edx and CHAR, 83 and 44 becomes 127 (111 1111)
            mov   eax, ecx                      //copy the XORed value of Char to EKey
            ror   al, 1                         //rotates al value by 1 bit to the right 127 (0111 1111‬)
            ror   al, 1                         //rotates al value by 1 bit to the right 191 (1011 1111‬)
            ror   al, 1                         //rotates al value by 1 bit to the right 223 (1101 1111‬) al value is now 239 (1110 1111‬)
            pop   edx                           //removes edx from the stack memory 
            mov   edx, eax                      //copy the value of EKey to edx 239 (1110 1111‬)
            pop   ebp                           //removes ebp from the stack memory
            ret                                 //proceeds to the line after the call instruction 
    }
}

//----------------- end of decrypt_chars function-----------------//




//************ MAIN PROGRAM *************************************************************************************

int main(void)
{
    int char_count(5);  // The number of actual characters entered (upto MAXCHARS limit).

    //cout << "\nPlease enter upto " << MAXCHARS << " alphanumeric characters:  ";
    //get_original_chars (char_count);  // Input the original character string to be encrypted 

    //*****************************************************

    // Open a file to store results (you can view and edit this file in Visual Studio)

    ofstream EDump;
    EDump.open("EncryptDump.txt", ios::app);
    EDump << "\n\nFoCA Encryption program results (" << StudentName << ") Encryption key = '" << EKey << "'";
    EDump << "\nDate: " << GetDate() << "  Time: " << GetTime();

    //*****************************************************
    // Display and save to the EDump file the string just input

    cout << "\n\nOriginal string =  " << OChars << "\tHex = ";
    EDump << "\n\nOriginal string =  " << OChars << "\tHex = ";

    for (int i = 0; i < char_count; i++)
    {
        cout << hex << setw(2) << setfill('0') << ((int(OChars[i])) & 0xFF) << "  ";
        EDump << hex << setw(2) << setfill('0') << ((int(OChars[i])) & 0xFF) << "  ";
    };

    //*****************************************************
    // Encrypt the string and display/save the result

    encrypt_chars(char_count, EKey);

    cout << "\n\nEncrypted string = " << EChars << "\tHex = ";
    EDump << "\n\nEncrypted string = " << EChars << "\tHex = ";
    for (int i = 0; i < char_count; i++)
    {
        cout << ((int(EChars[i])) & 0xFF) << "  ";
        EDump << ((int(EChars[i])) & 0xFF) << "  ";
    }

    //*****************************************************
    // Decrypt the encrypted string and display/save the result

    decrypt_chars(char_count, EKey);    //**** YOU NEED TO WRITE THE BODY OF THIS FUNCTION ***

    cout << "\n\nDecrypted string = " << DChars << "\tHex = ";
    EDump << "\n\nDecrypted string = " << DChars << "\tHex = ";
    for (int i = 0; i < char_count; i++)
    {
        cout << ((int(DChars[i])) & 0xFF) << "  ";
        EDump << ((int(DChars[i])) & 0xFF) << "  ";
    }
    //*****************************************************

    cout << "\n\n\n";
    EDump << "\n\n-------------------------------------------------------------";
    EDump.close();

    system("PAUSE");
    return (0);
} // end of whole encryption/decryption program --------------------------------------------------------------------

Upvotes: 0

Views: 1172

Answers (1)

ecm
ecm

Reputation: 2763

I ported your inline assembly to NASM 32-bit source and re-implemented the outer loop (encrypt_chars) in the same assembly language source too. I uploaded a repo with the updates and a short test program in C which can be compiled on Linux with gcc -m32. For building this you need NASM, gcc, and my macro collection. Here's the assembly source:


; CC-BY-SA, source:
; https://stackoverflow.com/questions/60787907/x86-assembly-encryption-to-decryption

%include "lmacros3.mac"

%ifidni __OUTPUT_FORMAT__, bin
    bits 32
%elifidni __OUTPUT_FORMAT__, elf
    global testfunc_encode
%endif

testfunc_encode:
    lframe near
    lpar dword, EKey
    lpar dword, length
    lpar dword, EChars
    lpar dword, OChars
    lpar_return
    lenter
    pushad

    mov esi, dword [ebp + ?OChars]
    mov ebx, dword [ebp + ?EChars]
    mov edi, dword [ebp + ?length]
    test edi, edi
    jz .end

.loop:
    movzx ecx, byte [esi]
    lea eax, [ebp + ?EKey]

    push ecx
    push eax
    call encrypt_3
    add esp, 8
    mov byte [ebx], dl

    inc esi
    inc ebx
    dec edi
    jnz .loop

.end:
    popad
    lleave
    lret


encrypt_3:
    lframe near
    lpar dword, data
    lpar dword, points_to_key
    lpar_return
    lenter
;            push ebp                            ; saves ebp to the stack memory
;            mov ebp, esp                        ; copies the value of esp to ebp
;            mov eax, [ebp + 8]                  ; adds 8 to the value of ebp then copy its value to EKey
;            mov ecx, [ebp + 12]                 ; adds 12 to the value of ebp (recently added 8) then copy the value to the encrypted character
    mov eax, dword [ebp + ?points_to_key]
    mov ecx, dword [ebp + ?data]
            push  edx                           ; puts the edx to the stack memory
            push  ecx                           ; puts CHAR to the stack memory
            push  eax                           ; puts EKey to the stack memory
            movzx eax, byte [eax]               ; Uses the EKey (z) inside eax as the eax memory address
            rol   al, 1                         ; rotate al by 1 bit to the left, 111 1010‬ (moves the 0 at the end to the beginning)
            not al                              ; invert each bit of al (1111 0100‬) becomes 0000 1011
            rol   al, 1                         ; rotates the inverted binary of al to the left by 1 bit
            rol   al, 1                         ; rotates al binary by 1 bit again to the left, 0001 0110‬
            mov   edx, eax                      ; copies the value of Ekey to edx, edx = 44
            pop   eax                           ; removes the eax register from the stack memory
            mov   byte [eax], dl                ; Uses the value of edx as the byte address of eax (Ekey)
            pop   ecx                           ; removes the ecx (EKey) from the stack memory
            xor ecx, edx                        ; implements the XOR operation between edx and CHAR, 83 and 44 becomes 127 (111 1111)
            mov   eax, ecx                      ; copy the XORed value of Char to EKey
            ror   al, 1                         ; rotates al value by 1 bit to the right 127 (0111 1111‬)
            ror   al, 1                         ; rotates al value by 1 bit to the right 191 (1011 1111‬)
            ror   al, 1                         ; rotates al value by 1 bit to the right 223 (1101 1111‬) al value is now 239 (1110 1111‬)
            pop   edx                           ; removes edx from the stack memory
            mov   edx, eax                      ; copy the value of EKey to edx 239 (1110 1111‬)
;            pop  ebp                            ; removes ebp from the stack memory
;            ret                                 ; proceeds to the line after the call instruction
    lleave , optimiserestoresp
    lret


%ifidni __OUTPUT_FORMAT__, elf
    global testfunc_decode
%endif

testfunc_decode:
    lframe near
    lpar dword, EKey
    lpar dword, length
    lpar dword, EChars
    lpar dword, OChars
    lpar_return
    lenter
    pushad

    mov esi, dword [ebp + ?OChars]
    mov ebx, dword [ebp + ?EChars]
    mov edi, dword [ebp + ?length]
    test edi, edi
    jz .end

.loop:
    movzx ecx, byte [esi]
    lea eax, [ebp + ?EKey]

    push ecx
    push eax
    call decrypt_3
    add esp, 8
    mov byte [ebx], dl

    inc esi
    inc ebx
    dec edi
    jnz .loop

.end:
    popad
    lleave
    lret


decrypt_3:
    lframe near
    lpar dword, data
    lpar dword, points_to_key
    lpar_return
    lenter
    mov eax, dword [ebp + ?points_to_key]
    mov ecx, dword [ebp + ?data]
            push  edx                           ; puts the edx to the stack memory
            push  ecx                           ; puts CHAR to the stack memory
            push  eax                           ; puts EKey to the stack memory
            movzx eax, byte [eax]               ; Uses the EKey (z) inside eax as the eax memory address
            rol   al, 1                         ; rotate al by 1 bit to the left, 111 1010‬ (moves the 0 at the end to the beginning)
            not al                              ; invert each bit of al (1111 0100‬) becomes 0000 1011
            rol   al, 1                         ; rotates the inverted binary of al to the left by 1 bit
            rol   al, 1                         ; rotates al binary by 1 bit again to the left, 0001 0110‬
            mov   edx, eax                      ; copies the value of Ekey to edx, edx = 44
            pop   eax                           ; removes the eax register from the stack memory
            mov   byte [eax], dl                ; Uses the value of edx as the byte address of eax (Ekey)
            pop   ecx                           ; removes the ecx (EKey) from the stack memory

%if 0
; xor cl, KEYBYTE
; ror cl, 3
            xor ecx, edx                        ; implements the XOR operation between edx and CHAR, 83 and 44 becomes 127 (111 1111)
            mov   eax, ecx                      ; copy the XORed value of Char to EKey
            ror   al, 1                         ; rotates al value by 1 bit to the right 127 (0111 1111‬)
            ror   al, 1                         ; rotates al value by 1 bit to the right 191 (1011 1111‬)
            ror   al, 1                         ; rotates al value by 1 bit to the right 223 (1101 1111‬) al value is now 239 (1110 1111‬)
%else
; rol cl, 3
; xor cl, KEYBYTE
    rol cl, 3
    xor cl, dl
    mov al, cl
%endif
            pop   edx                           ; removes edx from the stack memory
            mov   edx, eax                      ; copy the value of EKey to edx 239 (1110 1111‬)
    lleave , optimiserestoresp
    lret

I made a C test program which fills a 1 KiB buffer with a 32-bit LFSR, then tries encoding and decoding the data a few times with various keys. It will display "Error:" if an unexpected result happens. Here's the source:


// CC-BY-SA, source:
// https://stackoverflow.com/questions/60787907/x86-assembly-encryption-to-decryption

#include <stdint.h>
#include <stdio.h>
#include <string.h>

void testfunc_encode(uint8_t* OChars, uint8_t* EChars, uint32_t length, uint8_t EKey);
void testfunc_decode(uint8_t* OChars, uint8_t* EChars, uint32_t length, uint8_t EKey);

uint32_t next(uint32_t prior) {
    uint32_t shifted = prior >> 1;
    return ( (prior & 1) ? shifted ^ 0x80200003 : shifted);
}

int test1() {
    const uint32_t bufsize = 1024 / 4;
    uint32_t original[bufsize];
    uint32_t encoded[bufsize];
    uint32_t decoded[bufsize];
    uint32_t ii;
    uint32_t ll = 1;
    int rc = 0;

    for (ii = 0; ii < bufsize; ++ii) {
        original[ii] = ll;
        ll = next(ll);
    }

    testfunc_encode((void*)original, (void*)encoded, bufsize * 4, 0x00);

    testfunc_decode((void*)encoded, (void*)decoded, bufsize * 4, 0x00);

    if (memcmp((void*)original, (void*)decoded, bufsize * 4) == 0) {
        printf("Test 1 with same key succeeded!\n");
    } else {
        printf("Error: Test 1 with same key did not succeed.\n");
        rc = 1;
    }

    testfunc_decode((void*)encoded, (void*)decoded, bufsize * 4, 0x26);

    if (memcmp((void*)original, (void*)decoded, bufsize * 4) == 0) {
        printf("Error: Test 2 with different key succeeded!\n");
        rc = 1;
    } else {
        printf("Test 2 with different key did not succeed.\n");
    }


    testfunc_encode((void*)original, (void*)encoded, bufsize * 4, 0x26);

    testfunc_decode((void*)encoded, (void*)decoded, bufsize * 4, 0x26);

    if (memcmp((void*)original, (void*)decoded, bufsize * 4) == 0) {
        printf("Test 3 with same key succeeded!\n");
    } else {
        printf("Error: Test 3 with same key did not succeed.\n");
        rc = 1;
    }

    testfunc_decode((void*)encoded, (void*)decoded, bufsize * 4, 0xFF);

    if (memcmp((void*)original, (void*)decoded, bufsize * 4) == 0) {
        printf("Error: Test 4 with different key succeeded!\n");
        rc = 1;
    } else {
        printf("Test 4 with different key did not succeed.\n");
    }

    return rc;
}

int main() {
    int rc = 0;
    rc |= test1();
    return rc;
}

I made a test script in bash. It defaults to use ../lmacros/ as the source of the macro collection. You can change that (eg by running NASMINCLUDE=path/to/macros/ ./test.sh) if you put the macro files (lmacros1.mac and lmacros2.mac and lmacros3.mac) somewhere else. You can also specify different flags to NASM or the C compiler in this way. This is the script:

#! /bin/bash

set -e

[ -z "$NASM" ] && NASM=nasm
[ -z "$NASMOPT" ] && NASMOPT="-g"
[ -z "$NASMINCLUDE" ] && NASMINCLUDE=../lmacros/
[ -z "$CC" ] && CC=gcc
[ -z "$CCOPT" ] && CCOPT="-g -O0 -m32"

"$NASM" -felf $NASMOPT test.asm -o test.o -I "$NASMINCLUDE"
"$CC" $CCOPT main.c test.o -o main
./main

This is what it looks like to run it, if it succeeds:

$ NASM=oldnasm ./test.sh
Test 1 with same key succeeded!
Test 2 with different key did not succeed.
Test 3 with same key succeeded!
Test 4 with different key did not succeed.
$ 

There was only one specific part that I had to change from the encrypt_3 function to create decrypt_3. The key calculation remains exactly the same. We only need to change how that key byte value is used to transform the input byte, into what becomes the output byte. I'm quoting the specific part here:

%if 0
; xor cl, KEYBYTE
; ror cl, 3
            xor ecx, edx                        ; implements the XOR operation between edx and CHAR, 83 and 44 becomes 127 (111 1111)
            mov   eax, ecx                      ; copy the XORed value of Char to EKey
            ror   al, 1                         ; rotates al value by 1 bit to the right 127 (0111 1111‬)
            ror   al, 1                         ; rotates al value by 1 bit to the right 191 (1011 1111‬)
            ror   al, 1                         ; rotates al value by 1 bit to the right 223 (1101 1111‬) al value is now 239 (1110 1111‬)
%else
; rol cl, 3
; xor cl, KEYBYTE
    rol cl, 3
    xor cl, dl
    mov al, cl
%endif

I did not optimise the program, nor update your comments in the assembly source. You can probably transfer the specific solution of the decoding into your whole program, it isn't large.

Upvotes: 1

Related Questions