본문 바로가기
정보보안/Reversing

[Reversing] Assembly Language - Instruction Set

by Yoonsoo Park 2025. 3. 31.

명령어 집합 구조(Instruction Set Architacture; ISA)

명령어 집합 구조(ISA)는 하드웨어와 소프트웨어 간의 인터페이스 역할을 하며, CPU가 이해하고 실행할 수 있는 명령어들의 집합과 형식, 동작 방식을 정의한다. 

 

 명령어 집합 분류에는 CISC와 RISC가 있다. 아래의 표를 참고하자(내가 공부할 부분은 IA-32(x86)이기 때문에 CISC를 해볼 예정이다). 

 

일반적인 명령은 Opcode(operation code)와 하나 이상의 Operand로 구성된다. 

 

  • Opcode - MOV 같은 명령어
  • Operand - EIP와 같이 명령이 전달되는 인자(Opcode에 따라 Operand가 존재하지 않는 경우도 존재)

 

주소 지정 체계(Addressing Modes)

주소 지정 체계는 Opcode가 Operand의 위치를 지정하는 방법을 의미한다. 정의만으로는 감이 잘 오지 않을테니 주소 지정 체계의 종류를 간단하게 살펴보고, 예시를 통해 알아보자. 

 

주소 지정 체계는 c언어의 변수, 상수, 포인터와 유사하다. addressing mode에는 크게 Register addressing, Immediate addressing, Memory addressing이 있다. 

 

Register addressing(Reg)

  • = 변수 = 레지스터 이름
  • operand가 레지스터에 저장(적재)돼있는 값을 의미 
  • ex) EAX, EIP, ESP...

Immediate addressing(Imm)

  • = 상수
  • 메모리 접근 없이 상수 자체를 사용
  • ex) 0x123456

Memory addressing(Mem)

  • = 포인터
  • Direct addressing
    • [상수] 형태로 상수값이 가르키는 주소의 데이터를 의미
    • [0x4A393D]
  • Register Indirect addressing
    • [변수] 형태로 변수 위치에 들어간 레지스터에 적재된 값이 가리키는 주소의 데이터를 의미
    • [EAX]
  • Based register addressing
    • [Reg.base+Displacement] 형태로 레지스터에 저장된 값에 고정된 변위(offset, displacement)를 한 값이 가리키는 주소의 데이터
    • [EAX+4h]
  • Indexed addressing(추가)
  • based-indexed addressing(추가)

instruction set은 일반적으로 다음과 같이 [opcode] [dest] [source] 형식으로 사용 가능하다.

(산술 연산의 경우 첫번째 피연산자에서 두번째 피연산자를 연산한다)

 

Instructions

데이터 전달(data movement instructions)

  • MOV - 데이터를 복사
  • LEA - 주소 계산식을 평가해, 결과 주소를 레지스터에 저장
    • LEA EAX, [ECX] => ECX에 저장된 값이 가리키는 '메모리 주소'를 EAX에 복사
  • PUSH/POP - 데이터를 스택에 push(저장)/pop(꺼내어 지정된 위치에 저장)

산술 연산(Arithmetic Instructions)

  • INC/DEC - 피연산자 값을 1 증가/감소
  • ADD - 두 피연산자 값을 더해 결과를 첫 번째 operand 저장
  • SUB - 두 피연산자 간의 뺄셈
    • SUB EAX, [ECX] => 뺄셈한 결과를 EAX에 저장
    • destination - source
  • MUL - 곱셈을 수행하고 값을 주로 AX, DX 등의 레지스터에 저장
  • DIV - 나눗셈을 수행하고 몫과 나머지를 관련 레지스터에 저장

논리 연산(Logic and Shifting Instructions)

  • AND, OR, XOR, NOT
  • SHL/SAL - 비트를 왼쪽으로 이동시켜, 곱셈 효과를 내거나 비트 마스킹에 사용
  • SHR/SAR - 비트를 오른쪽으로 이동시켜, 나눗셈 효과를 내거나 부호를 유지하면서 이동

비교 연산(Comparison Instructions)

  • CMP - 두 피연산자를 비교, 결과에 따라 CPU의 조건 플래그(zero, sign, carry, overflow..)를 설정
  • TEST - 두 피연산자 간의 비트별 AND 연산을 수행하지만, 결과를 저장하지 않고 플래그만 설정
    • TEST BL, BL => BL이 0인지 확인(AND연산이기 때문에)
  • 일반적으로 비교 연산 아래에 흐름 제어문이 온다
  • 비교 연산이 끝나면 EFLAGS를 갱신한

흐름 제어(Jump and Conditional Jumps)

  • JMP - 무조건 지정된 주소로 점프하여 프로그램 흐름 변경
  • JE/JZ (Jump if Equal/Zero) - 비교 결과가 같거나, 결과가 0일 때 점프
  • JNE/JNZ - 비교 결과가 같지 않거나, 0이 아닐 때 점프
  • JL/JNGE, JLE/JNG, JG/JNLE, JGE/JNL
  • LOOP - 반복 실행을 위해 카운터 레지스터(ECX, CX)를 사용해 루프 구현

함수 호출/종료(Function Related)

  • CALL - 함수(서브루틴)를 호출하며, 현재 명령어 다음의 주소(복귀 주소)를 스택에 저장
  • RET - 스택에 저장된 반환 주소로 점프하여 함수에서 복귀

EIP는 흐름 제어함수 호출/종료 명령문으로만 바꿀 수 있다!

 

N: not

Z: zero

E: equal

G: greater

L: less

O: overflow

P: partiy

C: carry

A: above(초과)

B: below(미만)