Search code examples
cassemblyx86-64att

Hex Character bit rotation


I wrote the following x86-64 functions to be called in a C program: The first one takes in a 2-digit hexadecimal character and rotates its bit towards the right by one bit, i.e, if '12'(means 0x12 but 0x is not feeded as input) is rotated right by one bit to give '09'(0x09)

.file "rotate_right.s"
.section .rodata
.data
.globl rotate_right
.type   rotate_right, @function
.text
rotate_right:
pushq %rbp
movq %rsp,%rbp

pushq %rsi
pushq %rdi
pushq %rbx

subl $4, %esp
movb 8(%ebp), %al
sarb $1, %al

leave
ret
.size rotate_right, .-rotate_right

Similarly, this function rotates the bits to the left one position, so '12'(0x12) becomes '24'(0x24).

.file "rotate_left.s"
.section .rodata
.data
.globl rotate_left
.type   rotate_left, @function
.text
rotate_left:
pushq %rbp
movq %rsp,%rbp

pushq %rsi
pushq %rdi
pushq %rbx

subl $4, %esp
movb 8(%ebp), %al
sarb $1, %al

leave
ret
.size rotate_left, .-rotate_left

The create_key() function gets a four bit input like 0110 and outputs an 8-bit output as unsigned int i.e 01100110:

.file "create_key.s"
.section .rodata
ask_key:
.string "Enter 4-bit key:"
.data
.globl create_key
.type   create_key, @function
.text
create_key:
pushq %rbp
# stack holding
movq %rsp, %rbp
movl $ask_key, %edi
# printing the ask string
movl $0, %eax
# calling the C functions

call printf
movl $0,%esi
# rsi is set to 0. the key
pushq %rsi
# take it to the stack

# call getchar for getting each key bit
call getchar
popq %rsi
subl $48,%eax
# doing this will give us 1 or 0 if the we input 1 or 0
sall $1,%esi
# shift the key by one bit
orl %eax,%esi
# OR key and the sigle input
pushq %rsi
# push rsi to stack to save the value in rsi

# Do the above operation a total of 4 times
call getchar
popq %rsi
subl $48,%eax
sall $1,%esi
orl %eax,%esi
pushq %rsi

call getchar
popq %rsi
subl $48,%eax
sall $1,%esi
orl %eax,%esi
pushq %rsi

call getchar
popq %rsi
subl $48,%eax
sall $1,%esi
orl %eax,%esi

# copy first 4-bits of the key into %rax
movl %esi,%eax
#left shift the key 4 times
sall $4,%esi
# OR the secont 4-bits into %rax
orl %esi,%eax
leave
ret
# return the values and end the function
.size create_key, .-create_key

Here is the C-program,

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>

extern unsigned int create_key();
extern unsigned char rotate_left(unsigned char x);
extern unsigned char rotate_right(unsigned char x);

int main(){
/* This Part Takes The Input To Be Ciphered 
    And Prints The Hexadecimal Value*/
    
char word[200], outword[400], xor_hex[400], hex_rot[400], ch, hex[2];
unsigned int i_key, encodant, rotated;
int i, len, j;
/* i_key is the integer equvivalent of the cipher key*/

printf("enter cleartext:");

i = 0;
ch = getchar();
while(ch!='\n'){
    word[i] = ch;
    ++i;
    ch = getchar();
}
fflush(stdin);
len = i;
word[i] = '\0';
printf("%s\n", word);
printf("hex encoding:\n");
for(i = 0; i<len; i++){
    sprintf(outword+(i*2), "%02X", word[i]);
}
for(i=0;i<(2*len);i++){
    if(i%2==0 & i>0)printf(" ");
    if(i%20==0 & i>0)printf("\n");
    printf("%c", outword[i]);
}
printf("\n");

/* This Part Asks For The Cipher Key */
i_key =  create_key();

/* XOR Encoding of the Hex Cyphertext*/
for(i=0;i<len*2;i+=2){
    hex[0] = outword[i];
    hex[1] = outword[i+1];
    encodant = (int)strtol(hex, NULL, 16);
    sprintf(xor_hex+(i), "%02X", (i_key^encodant));
}

/* Encoding the text using bit rotation */
j=1;
for(i=0;i<len*2;i+=2){
    hex[0]=xor_hex[i];
    hex[1]=xor_hex[i+1];
    encodant = (int)strtol(hex, NULL, 16);
    if(j%2==0)rotated = rotate_right(encodant);
    else rotated = rotate_left(encodant);
    j++;
    sprintf(hex_rot+(i), "%02X", rotated);
}

/* Printing The Finished Ciphered Text */
printf("hex ciphertext:\n");
for(i=0;i<(2*len);i++){
    if(i%2==0 & i>0)printf(" ");
    if(i%20==0 & i>0)printf("\n");
    printf("%c", hex_rot[i]);
}
printf("\n");

return 0;
}

The function prototypes can't be changed, i.e rotate functions must be char and have char parameters, the create_key function is good appearently, but my code gives segmentation fault. I don't know what to do in this situation so any help is appreciated.


Solution

  • There is no need to do anything with the stack here. Take the argument from rdi (SysV) or rcx (Win32), put it in al, rotate and return:

        .file "rotate.S"
    
        .text
    
        .globl rotate_right
    rotate_right:
        mov %rdi, %rax
        shrb $1, %al
        ret
    
        .globl rotate_left
    rotate_left:
        mov %rdi, %rax
        shlb $1, %al
        ret
    
        .end
    

    Now that is GNU as syntax, it may require some adjustment for AT&T asm.

    To test it:

    #include <stdio.h>
    
    unsigned char rotate_left(unsigned char);
    unsigned char rotate_right(unsigned char);
    
    int main() {
        printf("%02x %02x\n", rotate_left(0x12), rotate_right(0x12));
        return 0;
    }
    

    Prints:

    24 09