본문으로 바로가기

어셈블리 프로그래밍 심화2

category Pwnable 2018. 7. 12. 20:36

1. 연산자


1). 사칙연산: +, -, *, /


a + b -> add




add operand1, operand2


operand1 = operand1 + operand2 



a - b -> sub




sub operand1, operand2


operand1 = operand1 - operand2 



a * b -> mul(부호없는 곱셈) - 1바이트 * 1바이트 = 2바이트(대부분)







al, ax, eax, rax의 값과 피연산자의 값을 곱한다.


mov eax, 0을 통해 eax 레지스터를 초기화한다.

mov al, 5를 통해 al(8bit)에 5를 대입한다.

mul byte [a]를 통해 10*5를 진행한다.



mul 심화(범위를 벗어날 때)





a = 9876, ax = 4500이다.

a * ax = 44,442,000 값이 나오고 2byte 크기가 담을 수 있는 범위를 넘어선다.

그렇다면 4byte로 확장한 후, 2byte 씩 나누어 dx, ax 저장한다.


44,442,000를 이진수로 나타내면 아래와 같다.

0000 0010 1010 0110 0010 0001 1001 0000


0000 0010 1010 0110를 10진수로 바꾸면 678이고, dx에 저장된다.


0010 0001 1001 0000를 10진수로 바꾸면 8592이고, ax에 저장된다.



a / b -> div     4바이트 / 4바이트 = 2바이트(대부분)



몫과 나머지가 한번에 계산되어 나온다.









cbw: convet byte to word(확장)

cwd: conver word to double word(확장)

cdq: conver double word to quad word(확장)


몫은 AL, 나머지는 AH에 저장된다.

0000 0011 0000 0001


0000 0011을 10진수로 바꾸면 1이다. 몫은 1

0000 0001을 10진수로 바꾸면 3이다. 나머지는 3


나눗셈 심화(범위가 더 클때)




2바이트가 넘는 44,442,000을 7412로 나누려고한다. 44,442,000은 2바이트를 넘기 때문에 DX, AX에 저장한다.


DX:AX 0000 0010 1010 0110 0010 0001 1001 0000


0000 0010 1010 0110를 10진수로 나타내면 678이다. DX

0010 0001 1001 0000를 10진수로 나타내면 8592이다. AX



eax = 5995(몫), edx = 7060(나머지)이다. 

eax * 7412 + edx = 5995 * 7412 + 7060 = 44,442,000이다.



2). 논리 연산: and, or, not, xor


and: 논리 곱

and operand1, operand2


operand1, operand2 모두 참(True, 1)이여야 결과 값이 참(True, 1)이 된다.



or : 논리 합

or operand1, operand2


oeprand1, operand2 둘 중 하나라도 참(True, 1)이면 결과 값이 참(True, 1)이 된다.


not: 논리 부정

not operand1


operand1의 비트를 반전 시킨다. 만일 참(True, 1)이면 결과 값이 거짓(False, 0)이 된다.


xor: 배타적 논리합

xor operand1, operand2


operand1과 operand2를 and 연산한다. 


operand1과 oeprand2의 참(True, 1), 거짓(False,0)이 같이 존재하지 않으면 참(True, 1), 그렇지 않으면 거짓(False, 0)이다.



3). 비트연산 : shift


- 비트를 민다.

- shr(right), shl(left)


 



mul 심화와 매우 비슷한 과정이다.


edx에는 위에 설명한것과 같이 0000 0000 0000 0000 0000 0010 1010 0110가 저장된다.

0000 0000 0000 0000 0000 0010 1010 0110를 16번 왼쪽으로 shift하면 어떻게 될까?

0000 0010 1010 0110 0000 0000 0000 0000가 된다.


eax는 0000 0000 0000 0000 0010 0001 1001 0000이 저장되어 있다.

0000 0010 1010 0110 0000 0000 0000 00000000 0000 0000 0000 0010 0001 1001 0000 을 10진수로 계산하면 아래와 같다.


44,442,000이다.


2. 예제 및 연습


1) 44,442,000 / 9876 를 어셈블리 프로그래밍 해보자.





shift 연산자에서 이용했던 예제를 이어서 사용했다.


현재 dword [result] 는 0000 0010 1010 0110 0000 0000 0000 0000 0000 0000 0000 0000 0010 0001 1001 0000 이다.

dword [result]를 오른쪽으로 16 shift를 하면 edx는 0000 0010 1010 0110 0000 0000 0000 0000 이다.

dword [result]를 0000ffffh와 and 연산을 하면 0000 0000 0000 0000 0010 0001 1001 0000이다.


div 하기 전에, eax는 0000 0000 0000 0000 0010 0001 1001 0000이고 edx는 0000 0010 1010 0110 0000 0000 0000 0000이다.

div를 통하면 결과적으로 44,442,000 / 9876을 하고 몫은 eax, 나머지는 edx에 저장된다.

eax = 4500, edx = 0이다.


2) 두 수를 입력 받아서 사칙연산 결과를 출력하는 어셈블리 프로그램을 작성하라.





지금 까지 배운것을 바탕으로 위와 같이 구현할 수 있다.