강좌와 팁

x86 어셈블리어 정리 날짜:2020-2-12 1:08:56 조회수:348
작성자 : Sd9ToU
포인트 : 30
가입일 : 2020-02-11 20:18:16
방문횟수 : 107
글 2개, 댓글 4개
소개 : ^~^
작성글 보기
쪽지 보내기
리버싱을 공부하면서 필수적이라고 생각되는 x86 어셈블리어들을 간단히 정리한 것입니다. 설명이 자세하지 않으므로 처음 공부하시는 분들에게는 적합하지 않으며 중간중간 생각이 나지 않을 때 참고하시면 좋을 것 같습니다.

<범용 명령어>

# 데이터 전송 명령어
MOV(Move) : 범용 레지스터 사이의 데이터를 복사한다; 메모리와 범용 레지스터 또는 세그먼트 레지스터 사이의 데이터를 복사한다; 즉시값을 범용 레지스터로 복사한다.
XCHG(Exchange) : 범용 레지스터 사이의 데이터를 교환한다; 메모리와 범용 레지스터 사이의 값을 교환한다.
PUSH(Push onto stack) : 스택을 4바이트 만큼 늘리고 즉시값을 넣는다.
POP(Pop onto stack) : 스택을 4바이트 만큼 줄이고 해당 피연산자로 값을 뺀다.
MOVZX(Move and zero extend) : 데이터를 복사하고 나머지 비트를 0으로 채운다.
MOVSX(Move and sign extend) : 데이터를 복사하고 나머지 비트를 부호 비트로 채운다.

# 이진 산술 명령어
ADD(Integer add) : 제 1피연산자와 제 2피연산자를 더한 값을 제 1피연산자로 이동한다.
ADC(Add with carry) : 제 1피산자와 제 2피연산자와 캐리를 더한 값을 제 1피연산자로 이동한다.
SUB(Subtract) : 제 1피연산자와 제 2피연산자를 뺀 값을 제 1피연산자로 이동한다.
SBB(Subtract with borrow) : 제 1피연산자와 제 2피연산자를 뺀 값에 빌림을 더하여 제 1피연산자로 이동한다.
IMUL(Signed multiply) : 피연산자들에 대하여 부호있는 곱셈을 수행한다.
MUL(Unsigned multiply) : 피연산자들에 대하여 부호없는 곱셈을 수행한다.
IDIV(Signed divide) : 피연산자들에 대하여 부호있는 나눗셈을 수행한다.
DIV(Unsigned divide) : 피연산자들에 대하여 부호없는 나눗셈을 수행한다.
INC(Increment) : 피연산자의 값을 1만큼 증가시킨다.
DEC(Decrement) : 피연산자의 값을 1만큼 감소시킨다.
NEG(Negate) : 피연산자에 대해서 보수를 취한다.
CMP(Compare) : 제 1피연산자에서 제 2피연산자를 뺀 결과로 플래그를 세팅한다.

# 논리 연산 명령어
AND : 비트 AND 연산을 수행한다.
OR : 비트 OR 연산을 수행한다.
XOR : 비트 Exclusive OR 연산을 수행한다.
NOT : 비트 NOT 연산을 수행한다. 

# 시프트와 회전 연산 명령어
SAR(Shift arithmetic right) : 오른쪽으로 산술 시프트를 n번 수행한다.
SHR(Shift logical right) : 오른쪽으로 논리 시프트를 n번 수행한다.
SAL/SHL(Shift arithmetic left/Shift logical left) : 왼쪽으로 산술/논리 시프트를 n번 수행한다.
ROR(Rotate right) : 오른쪽으로 로테이트를 n번 수행한다.
ROL(Rotate left) : 왼쪽으로 로테이트를 n번 수행한다.
RCR(Rotate through carry) : 오른쪽으로 Carry와 함께 로테이트를 n번 수행한다.
RCL(Rotate through carry) : 왼쪽으로 Carry와 함께 로테이트를 n번 수행한다.

# 비트와 바이트 연산 명령어
TEST(Logical compare) : 제 1피연산자와 제 2피연산자를 비트 AND연산한 결과로 플래그를 세팅한다.

# 제어 전송 명령어
JMP(Jump) : 해당 라벨로 분기한다.
Jcc(Jump if condition is met) : 만약 조건을 만나면 해당 라벨로 분기한다.
LOOP(Loop with ECX counter) : ECX != 0일 때까지 ECX를 감소시키고 해당 라벨로 분기한다.
LOOPZ/LOOPE(Loop with ECX and zero/Loop with ECX and equal) : ECX != 0 && ZF == 0일 때까지 ECX를 감소시키고 해당 라벨로 분기한다.
LOOPNZ/LOOPNE(Loop with ECX and not zero/Loop with ECX and not equal) : ECX != 0 && ZF != 0일 때까지 ECX를 감소시키고 해당 라벨로 분기한다.
CALL(Call procedure) : 프로시저를 호출한다.
RET(Return) : 프로시저를 호출한 곳으로 복귀한다.
INT(Interrupt) : 인터럽트를 발생시킨다.
ENTER(High-level procedure entry) : 중첩의 개수와 스택의 크기만큼 프로시저의 프롤로그를 수행한다.
LEAVE(High-level procedure exit) : 프로시저의 에필로그를 수행한다.

# 문자열 명령어
MOVS/MOVSB(Move string/Move byte string) : 문자열을 바이트 만큼 복사하고 인덱스 레지스터의 값을 증가시킨다.
MOVS/MOVSW(Move string/Move word string) : 문자열을 워드 만큼 복사하고 인덱스 레지스터의 값을 증가시킨다.
MOVS/MOVSW(Move string/Move doubleword string) : 문자열을 더블워드 만큼 복사하고 인덱스 레지스터의 값을 증가시킨다.
CMPS/CMPSB(Compare string/Compare byte string) : 문자열을 바이트 만큼 빼서 플래그를 세팅하고 인덱스 레지스터의 값을 증가시킨다.
CMPS/CMPSW(Compare string/Compare word string) : 문자열을 워드 만큼 빼서 플래그를 세팅하고 인덱스 레지스터의 값을 증가시킨다.
CMPS/CMPSD(Compare string/Compare doubleword string) : 문자열을 더블워드 만큼 빼서 플래그를 세팅하고 인덱스 레지스터의 값을 증가시킨다.
SCAS/SCASB(Scan string/Scan byte string) : dest와 src를 바이트 단위로 비교하여 플래그를 세팅하고 인텍스 레지스터의 값을 증가시킨다.
SCAS/SCASW(Scan string/Scan word string) : dest와 src를 워드 단위로 비교하여 플래그를 세팅하고 인텍스 레지스터의 값을 증가시킨다.
SCAS/SCASD(Scan string/Scan doubleword string) : dest와 src를 더블워드 단위로 비교하여 플래그를 세팅하고 인텍스 레지스터의 값을 증가시킨다.
LODS/LODSB(Load string/Load byte string) : src의 값을 바이트 만큼 EAX로 로드한다.
LODS/LODSW(Load string/Load word string) : src의 값을 워드 만큼 EAX로 로드한다
LODS/LODSD(Load string/Load doubleword string) : src의 더블워드 만큼 EAX로 로드한다.
STOS/STOSB(Load string/Load byte string) : EAX의 값을 바이트 만큼 dest로 저장한다.
STOS/STOSW(Load string/Load word string) : EAX의 값을 워드 만큼 dest로 저장한다
STOS/STOSD(Load string/Load doubleword string) : EAX의 더블워드 만큼 EAX로 저장한다.
REP(Repeat while ECX not zero) : ECX != 0일 때까지 ECX를 감소시키고 문자열 명령을 반복한다.
REPE/REPZ(Repeat while equal/Repeat while zero) : ECX != 0 && ZF == 0일 때까지 ECX를 감소시키고 문자열 명령을 반복한다.
REPNE/REPNZ(Repeat while not equal/Repeat while not zero) : ECX != 0 && ZF != 0일 때까지 ECX를 감소시키고 문자열 명령을 반복한다.

# I/O 명령어
IN(Read from a port) : 지정된 포트에서 EAX로 값을 읽는다.
OUT(Write to a port) : 지정된 포트로 EAX의 값을 쓴다. 

# ENTER와 LEAVE 명령어
ENTER(High-level procedure entry) : 중첩의 개수와 스택의 크기만큼 프로시저의 프롤로그를 수행한다.
LEAVE(High-level procedure exit) : 프로시저의 에필로그를 수행한다.

# 플래그 제어 (EFLAG) 명령어
STC(Set carry flag) : CF를 세팅한다.
CLC(Clear carry flag) : CF를 클리어한다.
CMC(Complement the carry flag) : CF에 대해서 보수를 취한다.
CLD(Clear the direction flag) : DF를 클리어한다.
STD(Set direction flag) : DF를 세팅한다.
LAHF(Load flags into AH register) : AH로 EFLAGS를 로드한다.
SAHF(Store AH register into flags) : EFLAGS에 AH의 값을 저장한다.
PUSHF/PUSHFD(Push EFLAGS onto stack) : 스택의 최상단에 EFLAGS를 넣는다.
POPF/POPFD(Push EFLAGS onto stack) : EFLAGS의 값을 해당 피연산자로 뺀다.
STI(Set interrupt flag) : IF를 세팅한다.
CLI(Clear the interrupt flag) : IF를 클리어한다.

# 난수 생성 명령어
RDRAND(Retrieves a random number generated from hardware) : Inter DRNG 의사난수를 생성하여 해당 레지스터에 저장하고 유효한 난수이면 CF를 1로 세팅하고 유효한 난수가 아니면 CF를 0으로 세팅한다.
RDSEED(Retrieves a random number generated from hardware) : Inter DRNG 엔트로피원을 해당 레지스터에 돌려준다.

# 기타 명령어
LEA(Load effective address) : 제 1피연산자로 제 2피연산자의 주소를 복사한다.
NOP(No operation) : 4바이트 명령어로 아무것도 수행하지 않는다. 


<x87 FPU 명령어>

# x87 FPU 데이터 전송 명령어
FLD(Load floating-point value) : ST(0)에 값을 넣고 스택 포인터를 조정한다.
FST(Store floating-point value) : 해당 피연산자로 ST(0)에 값을 뺀다.
FSTP(Store floating-point value and pop) : 해당 피연산자로 ST(0)에 값을 빼고 스택 포인터를 조정한다.
FILD(Load integer) : ST(0)에 정수값을 넣고 스택 포인터를 조정한다.
FIST(Store integer) : ST(0)의 (정수)값을 해당 피연산자로 뺀다.
FISTP(Store integer and pop) : ST(0)의 (정수)값을 해당 피연산자로 빼고 스택 포인터를 조정한다.
FXCH(Exchange register) : 해당 피연산자와 ST(0)의 값을 교환한다.

# x87 FPU 기본 산술 명령어
FADD(Add floating-point) : 지정한 피연산자(x86 FPU 레지스터)들의 값을 더하여 스택의 최상단(ST(0))에 저장한다.
FADDP(Add floating-point and pop) : 지정한 피연산자(x86 FPU 레지스터)의 값을 더하고 스택 포인터를 조정한다.
FIADD(Add integer) : 지정한 피연산자(정수값)와 ST(0)의 값을 더하여 스택의 최상단(ST(0))에 저장한다.
FSUB(Subtract floating-point) : 지정한 피연산자(x86 FPU 레지스터)들의 값을 뺄셈하여 스택의 최상단(ST(0))에 저장한다.
FSUBP(Subtract floating-point and pop) : 지정한 피연산자(x86 FPU 레지스터)들의 값을 뺄셈하고 스택 포인터를 조정한다.
FISUB(Subtract floating-point) : 지정한 피연산자(정수값)와 피연산자의 값을 뺄셈하여 스택의 최상단(ST(0))에 저장한다.

목록보기 삭제 수정 신고 스크랩

소엔 2월17일 12:11:58  

X86 어셈블리어 기계어 코드를 다 외워던 시절이 있었습니다. 지금이야 그럴 필요가 전혀 없지만요. B8 34 12가 MOV AX, 1234이며 AX 레지스터에 값을 넣는 명령인 식이에요. 어셈블리 무식해도 재미는 있었는데 요즘은 쓸 일이 거의 없더라구요. 오랜만에 어셈블리 니모닉을 보니 반갑네요.

Sd9ToU 2월17일 2:19:23  

음.. 학교 선배님 중에 코드게이트 파이널 1등 하신 분이 계신데 그분은 기계어까지 다 외우고 계시더군요^^;; 니모닉 인지는 모르겠지만 아무래도 오래 기억하고 좀 더 이해하기 위해서는 어셈블리어 뿐만 아니라 프로그래밍에서의 함수도 공부할 때 어떤 단어인지 정도는 찾아봐야 한다고 생각해요.


로그인하셔야 댓글을 달 수 있습니다.