기본 콘텐츠로 건너뛰기

어셈블리어(Assembly) 기초

0x01. 어셈블리 언어란? & 배우는 목적

CPU 에는 해당 프로세서에 명령을 내리기 위해 고유의 명령어 세트가 마련되어 있는데 이 명령어 세트를 기계어라고 한다이 기계어는 숫자들의 규칙조합임으로 프로그래밍에 상당히 난해하다그래서 이 기계 명령어를 좀더 이해하기 쉬운 기호 코드로 나타낸것(기계어와 1:1로 대응된 명령을 기술하는 언어)이 어셈블리어이다어셈블리 언어는 그 코드가 어떤 일을 할지를 추상적이 아닌직접적으로 보여준다논리상의 오류나수행 속도수행 과정에 대해 명확히 해준다는 점에서 직관적인 언어이다어셈블리 언어를 사용하면 메모리에대한 이해도도 높아진다어셈블리를 익히고배우는데 있어서는 여러 가지 목적이 있을 수있다컴퓨터 시스템&구조를 좀 더 깊게 이해하고메모리상의 데이터나 I/O기기를 직접 액세스 하는등의 고급언어에서는 할 수 없는 조작을위해서이다프로그램의 최적화 및 리버스 엔지니어링을 위해서도 필요하다.

+ 2줄 요약 +

어셈블리 언어는 기계어와 1:1 대응을 하는 언어이다.
어셈블리 언어를 배우면 시스템을 이해하는데 도움이 된다.


0x02. 어셈블리를 위한 기본 지식

(1) 기본적인 하드웨어

1) CPU

메모리에 있는 내용을 읽고쓰고 데이터를 메모리와 각 레지스터로 보낸다.프로그램의 명령을 해석하고 실행한다.하나의 프로세서는 12~14개의 레지스터를 가지고 있으며,CPU의 연산논리 장치는 숫자와 기호에 관한 연산자를 인식한다보통 이러한 장치들은 기본적인 연산만을 수행할 수 있다(덧셈뺄셈곱셈나눗셈숫 자비교). 퍼스널 컴퓨터는 한번에 처리할 수있는 비트수(Word) 따라서 분류된다.

2) RAM

반도체로 조립된 셀들의 집합프로세스가 프로그램을 실행시키고 작동하기위해서 필요한
정보들을 저장하는데 쓰인다각각의 셀들은 숫자값을 포함하고 주소가 정해질 수 있는 형
식이며 프로그램에서 흔히 메모리라고 하는 것들은 메인메모리램이라고 할 수 있다.

(2) 80x86 프로세서

1) CPU 레지스터 종류 : 범용 레지스터상태 레지스터플래그 레지스터
 - 레지스터 : CPU내부의 기억장소로 PC가 정보를 처리하기 위해서는 정보가 특정한 셀에 저장되어 있어야 한다이러한 셀을 레지스터라고 불린다레지스터들은 8또는 16비트 플립-플롭 회로들의 집합이다플립-플롭 회로란 두 단계의 전압으로 정보를 저장할 수 있는 장치이다낮은 전압은 0.5 볼트이고 높은 전압은 5볼트이다낮은단계의 에너지는 0으로 해석되고 높은 전압은 1이 상태는 보통 비트로 불리며 컴퓨터의 가장 작은 정보 단위이다.





레지스터의 구조 >

① 데이터 레지스터
데이터 레지스터는 각종 데이터 처리를 대상으로 하는 하는 32비트 레지스터 및 16비트 레지스터 일부를 프로그래머가 명령 중에서 자유롭게 지정을 할 수 있는 범용 레지스터이다.
: EAX, EBX, ECX ,EDX

② 포인터 레지스터
: ESP, EBP

③ 인덱스 레지스터 (Index register)
: ESI, EDI

④ 세그먼트 레지스터 (segment register)
: CS, DS, SS, ES


범용 레지스터 +
32Bit16Bit상위8Bit하위8Bit기능
EAXAXAHAL누산기(Accumulator, 중간 결과를 저장해 놓음)
레지스터라 불리며, 곱셈이나 나눗셈 연산에 중요하게 사용
EBXBXBHBL베이스 레지스터라 불리며 메모리 주소 지정시에 사용
ECXCXCHCL계수기(Counter)레지스터라 불리며 Loop등의 반복 명력에 사용
EDXDXDHDL데이터(Data)레지스터라 不利며 곱셈, 나눗셈에서EAX함께
쓰이며 부호 확장 명령 등에 사용 
ESISI  다량의 메모리를 옮기거나 비교할 때 그 소스(Source)의 주소를
가진다
EDIDI  다량의 메모리를 옮기거나 비교할때 그 목적지의 주소를 가리키다.
ESPSP  스택 포인터로 스택의 최종점을 저장한다.
EBPBP  ESP를 대신해 스택에 저장된 함수의 파라미터 지역 변수의
주소를 가리키는 용도로 사용된다.


세그먼트 레지스터 +
16Bit기능
ES보조 세그먼트 레지스터다. 두 곳 이상의 데이터 저장영역을 가리켜야 할 때 DS와 함께 사용된다.
하지만 32Bit 프로그램에서는 DS와 ES가 같은 영역을 가리키고 있기 때문에 굳이 신경 쓰지 않아도 된다.
CS코드 세그먼트를 가리키는 레지스터. 프로그래머 코드의 시작조소를 가지고 있다.
SS스택 세그먼트를 가리키는 레지스터. 스택의 시작 주소를 담고 있다.
스택 조작에 의해서 데이터를 처리하는 동작이 이루어 진다.
DS데이터 세그먼트를 가리키는 레지스터.
프로그래머가 정해놓은 데이터의 시작주소를 담고 있다.
FS보조 세그먼트 레지스터. FS, GS는 286 이후에 추가된 것으로 운영체제를 작성하는 게 아니라면 없듯이 여겨도 된다.
GS


상태 레지스터+
32Bit16Bit기능
EIPIPEIP는 현재 실행되고 있는 프로그램으 ㅣ실행코드가 저장된 메모리의 주소를 가리키는 레지스터로 프로그램의 실행이 진행됨에 따라 자동으로 증가하고 프로그램의 실행 순서가 변경되는 제어문이 실행될때 자동으로 변경괸다. 그래서 직접 접근해서 값을 저장하거나 읽거나 하는 일이 없기 때문에 응용 프로그램에서는 손 댈 일이 없는 레지스터이다.
EFLAGSFLAGS비타 단위의 플래그 들을 저장하는 레지스터로 아주 특별한 용도로 사용된다.


0x03. 어셈블리 명령어의 구성

어셈블리는 어셈블리어라고도 부르는데 이 어셈블리어는 명령어들의 조합이다인텔 CPU 안에는 이 명령어들이 회로로 구현되어 있어서 어셈블리 코드를 실행할 수 있다. CPU는 2진수로 모든 것을 처리하는데 어셈블리 명령어들도 2진수로 되어 있다하지만 2진수로 된 것
알아보기가 힘들어 mov, add와 같은 형태로 변환하여 보여진다아래 그림을 보자.


명령어 다음에 오는 레지스터 이름이나 값들은 operand라고 한다. mov %eax, %ebx에서 %eax 를 제1오퍼랜드, %ebx를 제2오퍼랜드라고 한다. mov %eax, %ebx는 C언어로 보면 ebx = eax의 경우와 같다. eax에 저장된 값을 ebx에 할당(assignment)한다.(특정 장소(주로 메모리상에서)에서 특정 장소(주로 레지스터)로 데이터를 읽어 와서 적재(load)).
 ‘L1:‘과 같은 명령은 직접적으로 기계어 코드로 번역되지 않고 분기명령(jmp)등에서 참조될 때에번지의 계산에 사용된다.

0x04. 주소 지정 방식의 이해

어셈블리는 메모리를 직접 다룰 수 있다는 점에서 우리가 어셈블리를 배우는 큰 이유가 될 수 있다이 메모리를 다루기 위해서 다양한  주소 지정방식이 있는데 어떤식으로 주소를 사용하고참조하는지 확인할 필요가 있다참고로 '0x04'에서 예를 들었던 'mov %eax,%ebx'의 경우는 레지스터 어드레싱(register addressing)이다.

1. 즉시 지정방식(immediate addressing)
 - mov $0x1, %eax  :  eax에 (16진수)1을 값을 넣는(할당방식이다.
 - 이렇게 메모리(기억장치)의 주소의 내용을 꺼내지 않고 직접 값을 대응시키는 방식을 즉 시지정방식이라고 한다.

2. 레지스터 지정방식(register addressing)
 - mov %esp, %ebp 레지스터 ebp에 레지스터 esp의 값을 넣는다.(할당 개념)
 나중에 알 수 있겠지만위의 명령은 스택포인터를 베이스 포인터에 넣는 명령으로 함수가 시작될때 ebp의 값(일종의 시작기준점)을 정하는 명령이다.
 - 레지스터에서 직접 레지스터로 값을 대응시키는 방식을 레지스터 지정방식이라고 한다.
 - 속도는 빠르지만 레지스터의 크기(32비트)로 인해 크기가 제한된다.

3. 직접 주소 지정방식(directly addressing)
 - mov %eax, $0x80482f2 주소 0x80482f2에 있는 값을 eax에 할당한다.
가장 일반적인 주소지정방식이며메모리의 주소를 직접 지정해서 바로 찾아오는 방식이 즉 eax레지스터에 0x80482f2주소의 내용을 로드(load)한다는 의미이다.

4. 레지스터 간접 주소 지정 방식
 - mov (%ebx), %eax
 : ebx의 값을 주소로 하여(간접적으로) eax레지스터에 할당
 - ‘( )’가 들어간다면 간접 지정이라고 볼 수 있다. ‘( )’의 의미는 괄호 안에 들어간 값의 주소이다.

5. 베이스 상대 주소 지정 방식
 - mov 0x4(%esi), %eax
 : esi레지스터에서 4(byte)를 더한 주소의 값을 eax레지스터에 할당한다.
 - 보통 레지스터의 크기가 4byte이기 때문에 레지스터 다음 주소를 의미한다문자열 열산이나 메모리 블록 전송등에 나오는 방식이다.

0x05. 어셈블리어 명령어 정리


0x06. 어셈블리 명령어 상세

명령어의 분류
1) 데이터 이동 : mov, lea
2) 논리연산 : add, sub, inc, dec
3) 흐름제어 : cmp,jmp
4) 프로시져 : call, ret
5) 스택조작 : push, pop
6) 인터럽트 : int

1) 데이터 전송
 1. mov (move data)
형식 : mov SOURCE, DESTINATION
기능 : SOURCE위치에 들어있는 데이터를 복사하여 DESTINATION위치에 저장.
원칙 메모리와 레지스터(모든 연산은 레지스터에 저장된뒤 이루어진다.) 사이의 데이터 이동레지스터와 레지스터 사이의 데이터 이동이나 값을 메모리나 레지스터에 대 입할 때 사용한다. (SOURCE와 DESTINATION의 크기가 동일해야 한다.)
      ! DESTINATION 레지스터가 CS가 될수 없다.(프로그램실행위치가 변경되기때문)
      (CS의 변경은 int, jmp, call, ret등의 명령으로 가능)
! SOURCE와 DESTINATION이 전부 메모리를 가르칠수 없다. (설계상 불가능)
! SOURCE가 직접지정방식일경우에는 DESTINATION은 CS일 수 없다.

 2. lea
형식 : lea SOURCE, DESTINATION
기능 : SOURCE OPERAND에서 지정된 주소를 DESTINATION으로 로드한다.
LEA의 주된 용도는 매개변수나 지역변수의 주소를 얻어오는 것이다.
예를 들어 C언어에서 지역변수나 매개변수에 &연산자를 사용한다면 컴파일러는
lea명령어를 생성한다.
원칙 : SOURCE OPERAND는 메모리에 위치해야하며변경될 주소는 index register나 DESTINATION에 정의된 주소여야 한다.

2) 논리연산 : add, sub, inc, dec

1. add
형식 : add opr1, opr2
기능 : opr2의 내용에 op1의 내용이 더해져서 그 결과를 opr2에 저장.
원칙 : ! 두 개의 오퍼랜드 모두에 메모리로 조합되는 것은 불가능.

2. sub (subtract)
형식 : sub opr1, opr2
기능 첫번째 오퍼랜드로 부터 2번째 오퍼랜드 의 내용을 뺀 다음 결과를 첫 번째 오퍼
원칙 : ! 메모리끼리는 뺄셈을 할수 없다.

3. inc (Increment)
형식 : inc DESTINATION
기능 : DESTINATION을 증가시키고 결과값을 다시 저장

4. dec (decrement)
형식 : dec DESTINATION
기능 : DESTINATION을 감소시키고 결과값을 다시 저장

3) 흐름 제어 : jmp, cmp
형식 : jmp proc
기능 프로그램의 흐름을 바꿀 때 사용. proc의 주소로 가서 그곳의 명령어를 실행.
if/else, loop(루프가 아직 끝나지 않았을때처음위치로 돌아가기 위해)
등에서 나타난다.

2. cmp
형식 : cmp value, value
ex) cmp %eax, 0 (eax레지스터의 값을 0과 비교한다.)
     je start        (비교 결과가 같다면 start로 분기한다.)
                     (같지 않다면 je 다음에 오는 명령어를 실행한다.)
기능 두값을 비교하고 비교결과에 따라 분기한다보통 레지스터나 메모리 및 숫자의 크기를 비교한다. cmp 명령어는 Zero, Sign, Overflow 등의 플래그를 set or clear 한다이 플래그의 결과에 의해서 Jcc 명령어들은 분기할 것인지를 결정한다보통 CMP 명령어 다음에 JE, JNE 등의 jmp관련 명령어가 위치한다.
원칙 : cmp 명령은 혼자 사용되지 않고 언제나 조건 점프 명령어나 조건 이동(mov) 명령어와 함께 사용된다.
조건 점프 명령어 : cmp 명령어의 결과에 따라 점프하는 명령어.


참고 *
Unsigned 계열 (부호가 없는 값)
je : jump equal - 비교 결과가 같을 때 점프
jne : jump not equal - 비교 결과가 다를 때 점프
jz : jump zero - 결과가 0일 때 점프, je와 같음. (cmp 명령에서 결과가 같으면 0을 출력)
jnz : jump not zero - 결과가 0이 아닐 때 점프
ja : jump above - cmp a, b에서 a가 클 때 점프
jae : jump above or equal - 크거나 같을 때 점프
jna : jump not above - 크지 않을 때 점프
jnae : jump not above or equal - 크지 않거나 같지 않을 때 점프
jb : jump below - cmp a, b에서 a가 작을 때 점프
jbe : jump below or equal - 작거나 같을 때 점프
jnb : jump not below - 작지 않을 때 점프
jnbe : jump not below or equal - 작지 않거나 같지 않을 때 점프
jc : jump carry - 캐리 플래그가 1일 때 점프
jnc : jump not carry - 캐리 플래그가 0일 때 점프
jnp/jpo : jump not parity / parity odd - 패리티 플래그가 0일 때 홀수일 때 점프
jp/jpe : jump parity / parity even - 패리티 플래그가 1일 때 짝수일 때 점프
jecxz : jump ecx zero - ecx 레지스터가 0일때 점프
Signed 계열 (부호가 있는 값)
jg : jump greater - cmp a, b에서 a가 클 때 점프
jge : jump greater or equal - 크거나 같을 때 점프
jng : jump not greater - 크지 않을 때 점프
jnge : jump not greater or equal - 크지 않거나 같지 않을 때 점프
jl : jump less - cmp a, b에서 a가 작을 때 점프
jle : jump less or equal - 작거나 같을 때 점프
jnl : jump not less - 작지 않을 때 점프
jnle : jump not less or equal - 작지 않거나 같지 않을 때 점프
jo/jno : jump overflow / not overflow - 오버플로 플래그가 1일 때 / 0일 때 점프
js/jns : jump sign / not sign - 사인(부호플래그가 1일 때(음수) / 0일 때(양수점프
조건 점프 명령을 조합하여 if ( a > b ), for, while등의 조건문 구현


4) 프로시져 : call, ret

1. call
형식 : call Target
기능 스택 상에서 CS를 다음에 오는 명령의 오프셋 어드레스를 PUSH하고 target으로 이동한다다른 함수로 제어를 옮긴다는 뜻이다. CALL 명령어 다음에 오는 명령어의 주소를 스택에 PUSH하고 주어진 주소로 제어를 옮긴다는 뜻(EIP를 변경시킴)
# CALL명령은 CALL명령 다음위치에 있는 명령의 주소를 스택에 push한다.

2. ret (return)
형식 : ret
기능 호출된 함수에서 호출한 함수로 복귀. esp에 있는 값을 꺼내서(pop) EIP레지스터에 할당한다, call명령 당시 push되었던 주소를 pop하여 eip에 넣는 것이다.

5) 스택조작 : push, pop

1. pop
형식 : pop DESTINATION
기능 스택 맨 윗부분(top)에서 하나의 워드를 DESTINATION에 로드(load)그리고 스택포인터는 그 바로 전의 데이터를 가리킨다(point).

2. push
형식 : push DESTINATION
기능 메모리상에 설정된 스택이라는 공간에 데이터를 저장한다스택의 가장 윗부분에
데이터를 저장스택 포인터(esp)도 워드크기만큼 증가한다.

6) 인터럽트 : int
형식 : int (interrupt-type)
기능 운영체제에 할당된 인터럽트 영역을 system call.

댓글

이 블로그의 인기 게시물

SSH 크랙 , 보안 :: 메두사(Medusa) [소개, 사용법 ] [패스워드 크래킹]

외부에서 서버를 관리하기 위해서는 Telnet 과 같은 원격 쉘을 이용하게 됩니다. 이런 원격 쉘은 시스템에 직접 접근할수 있기 떄문에 특별한 관리와 보안이 필요합니다. 그래서 나온것이 SSH 바로 보안 쉘 입니다. 기본적으로 이동하는 패킷이 암호화 처리 되기 떄문에 TELNET보다는 매우 안전하다고 볼수 있습니다. 오늘은 이 SSH를 크랙하는 방법과 대책에 대해서 약간 알아보겠습니다. 이번에 소개할 툴은 메두사 입니다. 메두사는 Broute Force  공격에 사용되는 툴입니다. 설치 데비안계열 ( 데비안 , Ubuntu , 쿠분투 주분투 등등) 에서는 apt-get install medusa 로 간단하게 설치 할 수 있습니다. 메두사로 SSH서버를 크랙하는 방법에 대해 알아보겠습니다. 메두사의 메뉴얼입니다. 구조는 간단합니다. 상대 SSH서버를 확인한 후에 메두사로 무차별 대입공격을 시도합니다. 물론 상대 시스템에는 로그가 남을수 있겠지요.  일단 실험에 쓰일 노트북(공격자) 데스크탑(피해자) 입니다. 공격자 OS : Debian Net : wlan0 IP   : 192.168.0.26 피해자 OS : BackTrack4 Net : eth0 IP   : 192.168.0.3 ssh :  OpenSSh ( SSH1) 실험에 쓰일 피해자(backTrack)입니다.  현재 SSH서버를 가동하고 아무작업없이 대기중입니다. 공격자는 포트스캐너와 각종 툴들을 이용해 정보를 수집후  피해자가 SSH서버를 이용한다는것과 OpenSSH(SSH1)을 사용한다는 것을 알아냇다는 전제하에  시작하겠습니다. 공격자는 메두사 툴을 이용해 BruteForce공격을 시작합니다. medusa -h 192.168.0.3 -u root -P /home/noon/NOON/pass.txt -M ssh 사용된 옵션을 살펴 보자면 -h   :   호스트 주소입니다.  고로    타켓 주소 -u   :   크랙할 유저의 이름입니다.     유저 목록을 파일로 만들어서 사용할

OllyDbg 64bit 실행방법

OllyDbg 1.1 은 기본적으로 64bit 환경을 지원하지 못합니다. 책의 디버깅 실습은 거의 대부분 OllyDbg 를 이용해서 진행됩니다.  그러나 OllyDbg 1.1 은 64bit 환경을 지원하지 못합니다.  <그림 1. Windows 7 64bit 에서 OllyDbg 1.1 실행시 예외 발생> 64bit OS 에서 "2장 Hello World 리버싱" 실습 예제 파일 HelloWorld.exe 를 OllyDbg 1.1 로 실행시키면 <그림 1>과 같이 예외가 발생하면서 ntdll.dll 모듈 영역의 코드에서 멈춰버립니다. (이것은 OllyDbg 1.1 의 버그입니다.) 64bit 환경에서 OllyDbg 사용할 수 있는 2 가지 방법 #1. 64bit OS + OllyDbg 2.0 OllyDbg 2.0 버전에서는 64bit에서 정상 실행 되지 않는 버그가 수정되었습니다. 다운로드 링크 :  http://www.ollydbg.de/odbg200.zip * 참고 최신 버전 OllyDbg 2.01 beta 2 는 실행 과정에 약간의 문제가 있습니다. 문제가 해결될 때까지는 OllyDbg 2.0 을 사용해 주시기 바랍니다. 위 링크에서 파일을 다운받아 압축을 해제한 후 실행하면 <그림 2> 와 같은 화면이 나타납니다. <그림 2 - Windows 7 64bit 에서 OllyDbg 2.0 으로 HelloWorld.exe 를 띄운 화면> <그림 2>의 화면을 책의  <그림 2.3>  처럼 보이게 하려면 다음과 같이 작업해 주시면 됩니다. 1) 내부의 CPU 윈도우를 최대화 시킵니다. 2) Code/Register/Dump/Stack Window 의 폰트를 변경합니다.    (각각의 창에서 마우스 우측 메뉴 - Appearance - Font - System f

인터넷 웹페이지 디버깅 피들러(fiddler) 사용법

인터넷 디벌깅 툴 피들러 입니다. 개발자들은 인터넷 디버깅 툴을 많이 사용하고 있는데요 인터넷 익스플러워 , 사파리 구글크롬등 디버깅 툴은 내장되어 있습니다.  하지만 원하는 값을 얻기 어렵거나 사용하기 어려운 점도 있습니다. 그래서 사용하기도 간편하고 필요한 기능도 많도 원하는 값을 쉽게 확인 할수 있는 디버깅 툴을 소개 해드리려 합니다. 알고 계시는 분도 많겠지만 피들러 (fiddler) 라는 툴입니다.  피들러에 대하 알아보도록 하겠습니다.  피들러(Fiddler) 설치 피들러 설치를 하기 위해 아래 사이트에 접속합니다.   http://www.telerik.com/fiddler 사이트에 접속하시면 FreeDownload 버튼이 보입니다. 클릭을 해서 피들러 설치를 진행합니다. ▶ 피들러는 닷넷 프레임워크를 사용하는데요 window 7 이상 제품군이시면  Fiddler for NET4을 선택하시고 미만이면 .net2를 선택 하세요  이제 Download Fiddler를 선택합니다.  ▶ 피들러 설치 진행화면이 나옵니다. I Agree를 클릭합니다.    ▶ 설치할 폴더를 선택 후 Install을 클릭합니다.    ▶ 설치가 완료되면 Close 를 클릭합니다.    ▶ 설치가 완료되면 브라우저를 새로 실행 하시고 도구> Fiddler를 선택합니다. 도구메뉴가 안보이시면 Alt를 누르시면 보입니다.    ▶ 우측에도 피들러 메뉴가 있습니다.  도구를 클릭 후 피들러를 클릭합니다.   ▶ 실행이 되면 아래와 같은 화면이 나오는데요  좌측 하든을 보시면 Capturing 가 보입니다. 캡쳐를 진행하는 중이구요 키보드중 F12키를 누르면 캡쳐 중지 다시 F12키를 누르면 캡쳐가 진행됩니다.  원하는 부