본문 바로가기

Learning/└◆Reversing

[참고]어셈블리 언어에 대해서_2

(5) 어셈블리(Assembly)

 

(5-1) 용어

기계어

종류 : CPU 마다 고유 기계어가 있음

모양 : CPU가 바로 해독할 수 있는 01로 구성

특징 : 사람이 이해하기 어려움

기타 : 컴파일을 할 필요가 없음

 

어셈블리어

종류 : CPU 마다 고유 어셈블리어 존재

모양 : 사람이 이해하기 쉽도록 OP-CODE 사용

특징 : 기계어와 1:1로 모든 명령이 대응

기타 : 어셈블러를 통해 기계어로 컴파일 해야 함


어셈블리(Assembly) 소개

기계어

어셈블리어

고급언어

55

98ES

83EC 08

C70424

57000000

E8 7E050000

C9

C3

PUSH EBP

MOV EBP,ESP

SUB ESP,8

MOV DWORD PTR [ESP],57

CALL <JMP.&msvcrt.putchar>

LEAVE

RETN

void aChar(void)

{

putchar('W');

}

                            <------- assemble

                            --------> disassemble

                            <--------------------------------------- compile

                            ---------------------------------------> decompile

 


어셈블리어 언어를 사용해야 하는 경우

어셈블리어가 고급언어에 대해서 갖는 장/단점

코드를 많이 줄이려고 할 때. -> 적은 메모리 사용

ex

어셈블리어)

냉장고를 열어라 -> 음식을 넣어라 -> 냉장고를 닫아라.

고급언어)

냉장고를 열어서 음식을 넣어라.

 

(5-2) 어셈블리(Assembly) 구성

  • Intel 문법과 AT&T 문법이 있다.

  • (윈도우) Intel 문법 사용  : add (Destination) (Source)

  • (리눅스) AT&T 문법 사용 : add  (Source)      (Destination) 

add -> mnemonic(opcode)     명령
eax -> operand              피연산자
ebx -> operand              

연상기호(mnemonic, opcode)

add 는 덧셈을 한다라는 명령을 인간이 알기 쉬운 문자열로 대응시킨 연상기호(Mnemonic)이다.

 

피연산자(operand)

  • 기계 코드의 명령들에 따라 피 연산자의 형태와 개수가 다름

  • 각각의 명령들은 고정된 수의 피연산자 수(보통 0~3)를 갖는다.

  • 레지스터: 이는 피연산자들은 CPU 레지스터 들에 직접으로 접근

  • 메모리: 이는 메모리에 저장된 데이터를 가리킴. 언제나 세그먼트 최상단 부터 오프셋 값으로 나타냄

  • 즉시 피연산자(Immediate): 명령 자체에 있는 고정된 값들, 명령자체에 저장, 코드 세그먼트에 저장

  • 묵시적 피연산자(Implied): 정확히 나타나지 않는다. 예를 들어 증가명령은 레지스터나 메모리에 1을 더한. 이때 1은 묵시적 피연산자로 부른다.

 

 

어셈블리 명령어 형식

() opcode                                              EX) std

() opcode operand1                                  EX) push eax

() opcode operand1, operand2                   EX) add 10, eax

() opcode operand1, operand2, operand3      EX) shld 16, edx, eax

 


오퍼랜드(operand)의 종류

명령의 대상이 되는 오퍼랜드에는 다음과 같이 3가지 종류가 있다.

레지스터, 메모리, 직접값

 

mov 레지스터, 레지스터 EX) mov ebx, eax

mov 레지스터, 메모리 EX) mov eax, Value /* Value : 미리 선언된 메모리 변수명 */

mov 메모리, 레지스터 EX) mov Value,eax

mov 직접값, 레지스터 EX) mov eax, 100

mov 직접값, 메모리 EX) mov 100, Value

 


(5-3) 명령의 종류(자주 사용되는 어셈블러 명령)

 

명령의 종류는

        () 산술 연산 명령 종류

        () 데이터 전송 명령 종류

        () 논리 연산 명령 종류

        () 제어 전송 명령 종류

        () 스트링 명령 종류

        () 프로세스 제어 명령 종류


 

(5-3-1) 산술연산명령 종류

 

기본적인 정수를 계산하는 명령의 종류이다.

 

add(Add)

덧셈명령, 캐리를 포함하지 않는 덧셈을 한다

() add $0x10,%esp            (해석) esp += 10 /* eax10를 가산 */

() add ecx,eax               (해석) eax += ecx /* eaxecx를 가산 */

sub(Subtract)

캐리를 포함하지 않는 뺄셈(뺄셈 연산 처리에 사용)

() sub $0xc,%esp             (해석) esp -= 0xc

inc(Increment)

오퍼랜드 값을 1만큼 증가한다.

() inc eax                   (해석) eax++ /* eax1을 가산 */

dec(Decrement)

오퍼랜드 값을 1만큼 감소한다.

() dec eax                   (해석) eax-- /* eax1을 감산 */

cmp(Compare)

두 오퍼랜드 비교, 두수를 비교하여 같으면 0, 다르면 1 또는 -1을 리턴하는 명령어이다. 두 데이터를 비교하여 이를 Flag RegisterZF(Zero Flag)에 같으면 0으로 다르면 1로 세팅한다. 두 오퍼랜드 값이 같다는 것을 비교하는 방법은 오퍼랜드를 뺀값이 0이면 참이고 아니면 거짓이다.

() cmp ecx,eax                 (해석) if (ecx == eax) ZF=1 

                                      else ZF=0

mul(Multiply)

AX와 오퍼랜드를 곱셈 후 결과를 AX에 저장한다.(곱셈 연산 처리에 사용)

div(Divide)

AX의 내용을 오퍼랜드로 나누어 몫은 AL에 나머지는 EAH, EDX로 저장한다.

기타 산술연산 명령

ADC (Add with Carry)                : 캐리를 포함한 덧셈을 수행한다.

SBB (Subtraction with Borrow)       : 캐리를 포함한 뺄셈을 수행한다.

NEG (Change Sign)                   : 피연산자의 2의 보수, 즉 부호를 반전한다.

AAA (ASCII adjust for add)          : 덧셈결과의 AL 값을 UNPACK 10진수로 보정한다.

DAA (Decimal adjust for add)        : 덧셈결과의 AL 값을 PACK 10진수로 보정한다.

ASS (ASCII adjust for subtract)     : 뺄셈 결과의 AL 값을 UNPACK 10진수로 보정한다.

DAS (Decimal adjust for subtract)   : 뺄셈 결과의 AL 값을 PACK 10빈수로 보정한다.

IMUL(Multiply(Unsigned))            : 부호화된 곱셈을 수행한다.

AAM (ASCII adjust for Multiply)     : 곱셈 결과의 AX 값을 UNPACK 10진수로 보정한다.

IDIV(Integer Divide(Signed))        : 부호화된 나눗셈

AAD (ASCII adjust for Divide)       : 나눗셈 결과 AX 값을 UNPACK 10진수로 보정한다.

CBW (Convert byte to word)          : AL의 바이트 데이터를 부호 비트를 포함하여 AX 워드로 확장한다.

CWD (Convert word to double word)   : AX의 워드 데이터를 부호를 포함하여 DX:AX의 더블 워드로 변환한다


(5-3-2) 데이터 전송 명령 종류

메모리, 범용레지스터, 세그먼트 레지스터로 참조되는 주소에 존재하는 데이터 전송

 

mov(Move) : RAM --> CPU(Register) or CPU(Register) --> RAM

데이터 이동하는데 사용. RAM 끼리의 연산은 이루어 지지 않으므로 RAM의 데이터를 레지스터로 옮기거나 레지스터의 데이터를 RAM으로 옮기는 작업을 처리할 때 주로 사용한다.


() mov $0x0,%eax                       (해석) EAX = 0   /* EAX 값을 0으로 대입한다. */

() mov ecx,eax                         (해석) EAX = ECX /* ECX 값을 EAX에 저장 */

push(Push) : --> RAM(stack)

오퍼랜드의 내용을 스택에 넣는다. 레지스터의 데이터 임시 보관등에 사용한다.

() push $0x8048680                     (해석) Stack0x8048680 값을 저장

pop(Pop) : <-- RAM(Stack)

스택으로 부터 값을 빼낸다. 레지스터의 데이터를 복원할 때 주로 사용한다.

() pop eax                                  (해석) Stack 값을 EAX에 저장

lea(Load Effective Address to Register) : RAM(주소의 값) --> CPU(Register)

유효주소를 레지스터로 로드(Load). RAM에서 CPU에 있는 레지스터에 데이터를 옮길때 로드(Load)

라는 단어를 사용, 반대로 레지스터에서 RAM으로 가는 경우 저장(Store)이라는 표현을 사용한다.

* RAM -- Load --> CPU(Register)

* RAM <-- Save -- CPU(Register)

() lea 0xffffffd8(%ebp),%eax           (해석) RAM(주소(0xffffffd8)의 값)eax 저장


기타 데이터 전송 명령

xchg(Exchange Register Memory with Register): 첫번째 피연산자와 두번째 피연산자를 바꾼다.

IN(Input from AL/AX to Fixed port) : 피연산자로 지시된 포트로 AX에 데이터를 입력한다.

OUT(Output from AL/AX to Fixed port) : 피연산자가 지시한 포트로 AX의 데이터를 출력한다.

XLAT(Translate byte to AL) : BX:AL이 지시한 테이블의 내용을 AL로 로드한다.

LDS(Load Pointer to DS): LEA 명령과 유사한 방식으로 다른 DS 데이터의 주소의 내용을 참조시 사용한다.

LES(Load Pointer to DS) : LEA 명령과 유사한 방식으로 ES 데이터의 주소의 내용을 참조시 사용한다.

LAHF(Load AH with Flags) : 플래그의 내용을 AH의 특정 비트로 로드한다.

SAHF(Store AH into Flags) : AH의 특정 비트를 플래그 레지스터로 전송한다.

PUSHF(Push flags) : 플래그 레지스터의 내용을 스택에 삽입한다.

POPF(Pop flags) : 스택에 저장되어 있던 플래그 레지스터 값을 삭제한다.


(5-3-3) 논리연산 명령 종류

 

연산부호가 논리연산을 지정하는 명령으로 자리옮김, 논리 합(OR), 논리곱(AND), 기호 변환등이 있다.

 

and(AND)

논리 and 연산, 두수의 곱셈 연산 후 결과를 참과 거짓으로 표현하는 것으로 교집합의 형태와 동일하다. 대응되는 비트가 둘다 1일 때만 결과가 1이고, 그 이외에는 모두 0

() and AX,10h

--------------------------------------

AX     1  0  0  0                                          /* if AX 값이 0x08h라면 이진수로 1000이다. */

0x10h  1  0  1  0

--------------------------------------

결과     1  0  0  0

--------------------------------------

or(OR)논리 or 연산, 두수의 덧셈 연산 후 결과를 참과 거짓으로 표현하는 것으로 합집합의 형태와 동일하다. 대응되는 비트 중 하나만 1이어도 결과가 1이고, 둘 다 0인 경우에만 0() or AX,10h--------------------------------------AX 1 0 0 0 /* if AX 값이 0x08h라면 이진수로 1000이다. */0x10h 1 0 1 0--------------------------------------결과 1 0 1 0--------------------------------------

xor(Exclusive OR)배타적 논리 합(OR) 연산, 두수가 같은 값을 가지면 거짓, 다른 값을 가지면 참을 반환하는 연산으로 초기화 연산이나 암호화 시에 주로 사용한다. 대응되는 비트 중에서 한 비트가 1이고 다른 비트가 0이면 1, 두개의 비트가 모두 0 또는 1일 때 0, 따라서 두개의 비트가 같으면 0, 다르면 1이다.() xor AX,10h--------------------------------------AX 1 0 0 0 /* if AX 값이 0x08h라면 이진수로 1000이다. */0x10h 1 0 1 0--------------------------------------결과 0 0 1 0--------------------------------------

not(Invert)오퍼랜드의 1의 보수, 각 비트별 반대의 값으로 변환하여 1의 보수화() not AX--------------------------------------AX 1 0 0 0 /* if AX 값이 0x08h라면 이진수로 1000이다. */--------------------------------------결과 0 1 1 1--------------------------------------

test(And Function to Flags, no result)첫번째 오퍼랜드와 두번째 오퍼랜드를 and 하여 그 결과로 플래그 세트, and 연산과 같으나 연산 결과를 저장하지 않고 그 결과를 Flag Register에 저장한다. 데이터 두 값을 비교할 때 사용한다. 데이터의 변경 없이 단순 비교에 사용된다.() test %eax,%eax (해석) if(eax == 0) ZF=1 else ZF=0

ror(Rotate Right)오른쪽으로 오퍼랜드만큼 회전 이동(오른쪽으로 Rotation 시키는 연산)

rol(Rotate Left)왼쪽으로 오퍼랜드 만큼 회전 이동(왼쪽으로 Rotation 시키는 연산)

기타 논리연산 명령SHL/SAL(Shift Left/Arithmetic Left) : 왼쪽으로 피연산자만큼 자리 이동SHR/SAR(Shift Right/Shift Arithmethic Right) : 오른쪽으로 피연산자만큼 자이 이동RCL(Rotate through carry left): 자리올림(Carry)을 포함하여 왼쪽으로 피연산자 만큼 회전 이동RCR(Rotate through carry Right): 자리올림(Carry)을 포함하여 오른쪽으로 연산자만큼 회전이동

 

 

5-3-4) 제어 전송 명령 종류

 

점프(분기, Jump), 조건 점프(조건 분기, Conditional jump), 루프(Loop), 호출(Call)과 리턴(Return) 연산등으로 프로그램의 흐름 제어

 

JMP(Unconditional Jump)프로그램을 실행할 주소 또는 라벨로 이동한다.() jmp 04001000 (해석) if(무조건) 04001000 번지로 jump

JE(Jump Equal)/JZ(Jump Zero)(점프조건) ZF == 1() je 04001000 (해석) if(ZF == 1) 04001000 번지로 jump

JNE(Jump not equal)/JNZ(Jump not zero)(점프조건) ZF == 0() jne 04001000 (해석) if(ZF == 0) 04001000 번지로 jump

call(Call)함수(프로시저) 호출시 사용된다. PUSH(EIP) + JMP(jump)의 두가지 기능을 하는 것으로 함수 호출시 그 함수의 복귀 주소를 pushstack에 저장 시키며 jmp를 이용하여 그 함수로 이동한다.() call 0x80483a8 <printf> (해석) 0x80483a8 번지의 printf() 호출(push + jump)

ret(Return)함수에서 호출(call)한 위치로 돌아갈때 사용한다. POP(EIP) + JMP(jump)의 두가지 기능을 하는 것으로 함수 지역으로 복귀한다.

기타 제어 전송 명령JC(carry flag set) JNC(not carry flag set)JA/JNBE(above/not below nor equal)JAE/JNB(above or equal/not below)JB/JNAE(below/not above nor equal)JL/JNGE(less/not greater nor equal)JBE/JNA(below or equal/not above)JGE/JNL(greater or equal/not less)JLE/JNG(less or equal/not greater)JNP/JPO(not parity/parity odd)JNS(not sign)JO(overflow)JP/JPE(partity/parity even)JS(sign)JCXZ(CX zero)INT(interrupt) : 인터럽트가 호출되면 CS:IP(code segment:instruction pointer)와 플래그를 스택에 저장, 그 인터럽트에 관련된 서브 루팅이 실행LOOP(loop CX times) : 문장들의 블록을 지정된 횟수만큼 반복한다. CX는 자동적으로 카운터로 사용되며, 루프가 반복할 때 마다 감소한다.

 

* above, below : 부호 없는 두 수의 크기 관계

* greater, less : 부호 있는 두 수의 크기 관계

 

(5-3-5) 스트링(Strings) 명령 종류

 

바이트로 구성된 스트링(Strings of bytes)을 메모리 내에서 전송

 

데이터 전송 명령REP(Repeat) : ADDMOVS와 같은 작동 코드의 앞에 위치, CX0이 될 때까지 뒤에 오는 스트링 명령 반복MOVS(Move String) : 바이트, 워드, 더블워드를 옮기는 명령. MOVSB, MOVSW, MOVSD 등이 있다. CMPS(Compare String) : DS:SIES:DI의 내용을 비교한 결과에 따라 플래그를 설정한다.SCAS(Scan String) : AL 또는 AXES:DI가 지시한 메모리 내용을 비교한 결과에 따라 플래그를 설정한다.LODS(Load String) : SI 내용을 AL 또는 AX로 로드한다.STOS(Store String) : AL 또는 AXES:DI가 지시하는 메모리에 저장한다.

 

(5-3-6) 프로세스 제어 명령 종류

 

CLC(claer carry)

CMC(Complement Carry)

CLD(Clear Direction)

CLI(Clear Interrupt)

STD(Set Direction)

STI(Set Interrupt)

WAIT(wait)

ESC(Escape to External device)