Tuuna Computer Science

[어셈블리어] 시저암호 암호화 with Assembly 본문

Assembly

[어셈블리어] 시저암호 암호화 with Assembly

GuTTe 2018. 11. 3. 00:22
C로 시저암호(카이사르암호) 암호화와 복호화를 먼저 작성하고 이를 바탕으로 어셈블리어로 작성하려 한다.

먼저 복호화 구간은 조금 복잡해서 먼저 암호화 구간만 진행했는데 아마 내일 부터 다시 복호화 구간을 만들어내지 않을까 생각해본다... ㅎ

코드는 주석을 대충달았는데 알아서 잘 해석하길 바랍니다.

또한 %include "asm_io.inc"는 Pual Carter 교수가 만든 include파일인데 print_nl을 사용하기 위해서다 이 파일이 없다면 지우고 print_nl을 지우길 바람.

;일단 필요한 함수 strlen, strcpy구현

%include "asm_io.inc"

segment .bss

segment .data
    format1 db "%s", 0
    format2 db "%d", 0
    print1 db "input your key(0~25) : ", 0

segment .txt
    global asm_main
    global strlen_s ;문자열의 길이를 체크할 함수 구현       
    global strcpy   ;문자열을 복사할 함수 구현
    global crypto   ;평문을 암호화 시킬 함수
    global encrypto ;암호문을 복호화 시킬 함수
    extern printf
    extern scanf
    extern gets
    extern strlen
    
asm_main:
    push ebp
    mov ebp, esp
    sub esp, 80 ;buffer
    sub esp, 8 ;문자열의 길이, key value  

    lea eax, [ebp-80] ;buffer의 공간 즉, 80바이트 만큼 평문을 처리할 것이다.
    push eax
    call gets    ;gets함수를 통해 buffer의 시작주소를 인자로 준다.
    add esp, 4

    lea eax, [ebp-80]
    push eax
    push format1
    call printf
    add esp, 8

    call print_nl ;개행문자를 출력
    
    lea eax, [ebp-80] ;버퍼의 시작주소를 따온다.
    push eax ;string push!
    call strlen_s ;
    ;call strlen_s ;strlen 호출  
    add esp, 4

    mov [ebp-84], eax ;plain의 문자열 길이 변수(평문의 길이 exclude NULL)
;input key
    push print1    
    push format1
    call printf
    add esp, 8

    lea eax, [ebp-88] ;key value (KEY값)
    push eax
    push format2
    call scanf
    add esp, 8

    lea eax, [ebp-80]     ;buffer ebp+16(평문이 있는 버퍼의 주소값)
    push eax    ;스택에 푸시
    push dword [ebp-84] ;length ebp+12 평문의 길이 푸시
    push dword [ebp-88] ;key    ebp+8  키의 값 스택에 푸시
    call crypto ;암호화 진행 함수  
    add esp, 12    ;인자정리

    lea eax, [ebp-80]
    push eax
    push format1
    call printf
    add esp, 8
    call print_nl

    add esp, 88
    leave
    ret

strlen_s: ;문자열의 길이를 반환하는 함수 널문자는 배제 +8
    push ebp
    mov ebp, esp
    mov esi, [ebp+8] ;버퍼의 주소를 땀
    xor ecx, ecx
    jmp strlen_start_len
    
strlen_start_len:
    lodsb
    cmp al, 0x0 ;널까지하고 앞에 개행을 널로 바꿔주자
    je strlen_end
    inc ecx
    ;add esi, 1
    jmp strlen_start_len

strlen_end:
    mov eax, ecx ;return string length
    pop ebp
    ret

strcmp: ;문자열을 카피해주는 함수 널문자 포함
    push ebp
    mov ebp, esp

    pop ebp
    ret

crypto:
    push ebp
    mov ebp, esp
    xor ecx, ecx
    mov esi, [ebp+16]  ;버퍼의 주소를 esi로 줌
    mov edi, [ebp+16]  ;버퍼의 주소를 다시 edi로 줌 (edi에는 최종으로 값이 변경된 간접연산)
    mov ecx, [ebp+12]  ;
    xor eax, eax
    xor ebx, ebx

crypto_starting:  ;[ebp+8]key [ebp+12]length [ebp+16]buffer
    xor eax, eax   
    lodsb ;al = [esi], esi+=1 

    cmp eax, 0x20    ;문자가 space인지(공백) 비교한다.
    je crypto_set_space

    mov ebx, [ebp+8] ;key value
    sub eax, 0x41 ;   'A'의 값을 빼서 offset을 구한다.
    add eax, ebx
    mov ebx, 26    ;나눌 수
    CDQ    ;32bit레지스터를 eax:edx로 확장한다. 여기서 eax에는 몫이, edx에는 나머지가 들어간다.
    idiv ebx ;edx에는 나머지가 들어감
    add edx, 0x41 ;다시 아스키코드 값 'A'의 값을 더해서 암호화된 값을 edx에 넣는다.
    mov al, dl    ;최종적으로 나온 값을 al에 넣고
    stosb         ;[edi] = al => add edi, 1한다. 즉, edi에 넣는다.
    loop crypto_starting  ;다시 루프

crypto_end:
    leave
    ret
    
crypto_set_space:
    dec ecx
    stosb    ;공백일 경우 공백을 다시 넣는다.
    jmp crypto_starting


Comments