Search code examples
assemblyx86masm

Having trouble making this assembly procedure work in Visual Studio


I'm trying to solve this question that wants me to encrypt a message by rotating the bits of each 10 bytes of a message to the left or to the right according to a certain key, for example:

key BYTE -2, 4, 1, 0, -3, 5, 2, -4, -4, 6

Where the sign indicates the direction of rotation, negative being to the left, positive to the right. The numbers indicate the magnitude of rotation. So the first byte of the message will be rotated twice to the left, the second 4 times to the right and so on and we do the same with the 11th and 12th byte and so on until the end of the message.

When I call this procedure, nothing happens to the message stored in memory, however:

EncryptR PROC USES ebx ecx esi,
ptrkey: PTR BYTE, ; pointer to the key array
ptrmessage: PTR BYTE, ; pointer to the plaintext message
mlength: DWORD ; length of the message array
; -----------------------------------------------------------------------------

mov ecx, mlength 
    inc ecx
    mov edx, [ptrkey+10]
    ; mov edi, ptrmessage
    L2:
    mov esi, ptrkey 
    dec ecx 
    cmp ecx, 0 
    je endloop
    L1:
    push ecx
    mov cl, [esi]
    cmp cl,0
    ja Skip1
    neg cl
    rol [ptrmessage], cl
    jmp Skip2
    Skip1: 
    ror [ptrmessage], cl
    Skip2: 
    pop ecx 
    inc esi 
    inc ptrmessage
    cmp [esi], edx
    je L2
    LOOP L1

    endloop:
    ret

I've tried using edi to point to the message but it doesn't work according to the syntax of the rotate instructions apparently. I've used ptrmessage directly for now so that I avoid build errors. I'm calling the procedure using invoke and have already declared it using the PROTO directive. I've tried doing it in a way which would reset the pointer of the key array to the first element once it is out of bounds while the message pointer keeps going.

MOV edx, offset Message1 
    call Strlength
    Invoke EncryptR, ADDR key, addr Message1, eax

I'm not sure what's the problem, there's the possibilty of jumping to the endloop label prematurely which would explain it but it seems obvious that that wouldn't happen the first time round. Is there an issue with the way I have been using the rotate instructions?


Solution

  • There's a couple of issues. First of all ja is used for unsigned comparisons so it won't work for detecting values <0. Use jg (jump if greater) instead.

    When you use Invoke MASM, does prepare a frame for you and passes parameters via stack, those are available inside the method, but if you see those ptrmessage in a debugger outside VS, those will be pointers to the addresses on the stack and not to the content of the message.

    00401036 d3450c     rol     dword ptr [ebp+0Ch], cl
    

    That's why you do not see and effect of the rol as it doesn't rol the bytes but the pointer. Not sure if MASM has the syntax to do this in a proper way, but you can always get the address to a register (say edi) and operate on that. In such case you would have to specify the size of data too (byte ptr).

    Taking the following into consideration, I would write the EncryptR something like (changed lines makered with ;*)

    EncryptR PROC USES ebx ecx esi,
      ptrkey: PTR BYTE, ; pointer to the key array
      ptrmessage: PTR BYTE, ; pointer to the plaintext message
      mlength: DWORD ; length of the message array
    ; -----------------------------------------------------------------------------
      mov ecx, mlength 
      inc ecx
      mov edx, ptrkey
      add edx, 10           ;*
      mov edi, ptrmessage ;*
    L2:
      mov esi, ptrkey 
      dec ecx 
      cmp ecx, 0 
      je endloop
    L1:
      push ecx
      mov cl, [esi]
      cmp cl,0
      ja Skip1               ;*
      neg cl
      rol byte ptr [edi], cl ;*
      jmp Skip2
    Skip1: 
      ror byte ptr [edi], cl ;*
    Skip2: 
      pop ecx 
      inc esi 
      inc edi
      cmp esi, edx
    je L2
      LOOP L1
    
    endloop:
      ret
    EncryptR ENDP