어셈블리[1].쉘코드

Download Report

Transcript 어셈블리[1].쉘코드

어셈블리
-0-
어셈블리 구조
 어셈블리는 다음과 같이 다섯 영역으로 구성된다.

레이블(Label), 명령(OP-code), 인수 1(Operand 1), 인수 2(Operand 2), 주석(comment)
 레이블
 직접적인 수행과는 관계가 없으며 jmp, call 을 통해서 참조할때 사용된다.
 C 언어의 goto 문장에서 사용하는 레이블(레이블명:)과 같이 사용된다.
 명령
 기종에 따라 약간의 차이가 있다.





인수
인수에 따라 명령어 구사가 달라진다.
movb $0x1, %eax  1바이트 데이터를 eax 레지스터에 저장한다.
movw $0x1, %eax  2바이트(word) 데이터를 eax 레지스터에 저장한다.
movl $0x1, %eax  4바이트(long) 데이터를 eax 레지스터에 저장한다.
실습
포인트
어셈블리
기초
명령어
-1-
어셈블리 구조(실습 포인트)
 eax 에 4 바이트 형의 1 을 저장하라.
 eax 에 들어있는 값에 1을 더하라.
 eax 에 들어있는 값에서 1을 빼라.
 eax 의 값에서 1을 증가시켜라.
 eax 의 값에서 1을 감소시켜라.
 label_123 위치로 분기하라.
 서브루틴(sub1) 을 호출하라.
 서브루틴에서 원래의 위치로 복귀하라.
 시스템콜을 위한 인터럽트를 발생시켜라.
 eax 에 ‘esi+8’ 의 주소를 저장하라.
 ebp 값을 스택에 저장하라.
 스택에 저장된 값을 꺼내어 esi 에 저장하라.
-2-
어셈블리 구조(문제 풀이)
























eax 에 4 바이트 형의 1 을 저장하라.
mov1 $0x1, %eax
eax 에 들어있는 값에 1을 더하라.
addl $0x1, %eax
eax 에 들어있는 값에서 1을 빼라.
subl $0x1, %eax
eax 의 값에서 1을 증가시켜라.
incl %eax
eax 의 값에서 1을 감소시켜라.
decl %eax
label_123 위치로 분기하라.
jump label_123
서브루틴(sub1) 을 호출하라.
call sub1
서브루틴에서 원래의 위치로 복귀하라.
ret
시스템콜을 위한 인터럽트를 발생시켜라.
int $0x80
eax 에 ‘esi+8’ 의 주소를 저장하라.
leal 0x8(%esi), %eax
ebp 값을 스택에 저장하라.
push %ebp
스택에 저장된 값을 꺼내어 esi 에 저장하라.
pop %esi
-3-
어셈블리 - 인텔계열과 AT&T 계열 비교
 Register naming
 인텔 계열은 아무것도 붙지 않지만 AT&T 계열은 명령어 앞에 ‘%’ 가 붙는다.
 인텔 : ecx
AT&T : %ecx
 Source, Destination Ordering
 인텔 계열은 오른쪽에서 왼쪽으로 대입되고 AT&T 계열을 반대로 왼쪽에서 오른쪽으로 대입된다.
 인텔 : mov ecx, ebx
AT&T : movl %ebx, %ecx
 Operation size specification
 레지스터의 크기는 정해주는 것이 좋다(b, w, l).
 인텔 : mov cx, bx
AT&T : movw %bx, %cx
 Constant value/immediate vale format
 AT&T 계열은 value 앞에 ‘$’ 가 붙는다.
 인텔 : mov ebx, _hack
AT&T : movl $_hack, %ebx
-4-
어셈블리 - 인텔계열과 AT&T 계열 비교
 Referencing memory
 32 비트 주소를 어드레싱
 인텔 : [base + index * scale + immediate32]
 AT&T : immediate_value(32){base, index, scale}
 특정 포인터를 어드레싱
 인텔 : [ebx]
 AT&T : (%eax)
 C 언어 변수를 어드레싱
 인텔 : [_hack]
 AT&T : _hack
실습
포인트
해킹개념
상시
유지용
문제
 오프셋 어드레싱
 인텔 : [ebx +1]
 AT&T : 1(%ebx)
-5-
해킹개념 상시 유지용 문제 - Brutus Attack(실습 포인트)
 221.154.130.98 (추후 변동가능 있음) 를 대상으로 FTP 서버공격으로 ID/PW 를 획득하라.
 아이디/비밀번호를 획득한 후에 숨겨져 있던 쉐도우 파일을 크랙하라.
• 힌트
크랙용 사전이 생성되는 시간 관계상 여기서 제공되는 DIC 생성기의 범위는 91919190 부터 91919210 으로 제한한다.
-6-
해킹개념 상시 유지용 문제 - Brutus Attack(문제 풀이)
 221.154.130.98 (추후 변동가능 있음) 를 대상으로 FTP 서버공격으로 ID/PW 를 획득하기.
 FTP 크랙 프로그램 다운로드 위치
 http://hackersnews.org/tools/MFTPB.exe
 Dic Generator(사전 생성기) 다운로드 위치
 http://hackersnews.org/tools/numero.zip
 샘플용으로 생성된 사전 다운로드 위치
 http://hackersnews.org/tools/RESULT.TXT




위의 결과로 나온 아이디와 비밀번호를 이용하여 FTP 클라이언트을 이용하여 쉐도우을 빼낸다.
아이디/비밀번호를 획득한 후에 숨겨져 있던 쉐도우 파일을 크랙하기.
쉐도우(shadow) 파일 크랙용 크래커 다운로드 위치
http://hackersnews.org/tools/john_win.zip
-7-
어셈블리 - 메모리
 1바이트(byte)가 메모리의 기본단위이다.
 2바이트(word), 4바이트(double word), 8바이트(quad word), 16바이트(paragraph)
 메모리의 데이터는 숫자로 구성되어 있음.
 ASCII 는 하나의 문자를 코딩하기 위해 1바이트를 사용.
 Unicode 는 하나의 문자를 코딩하기 위해 2바이트를 사용.
-8-
어셈블리 – segment:offset

16비트 BUS 의 한계를 극복하기 위해 20 비트 BUS를 사용하기 위해 고안.

segment 는 바이트의 집합.

offset 는 메모리의 접근 위치를 지정하기 위함.

physical address = segment x 10h + offset

31337:12345 의 물리적 주소 = 325715
313370
31337 x 10h
+ 12345
------325715
-9-
어셈블리 - 기초 명령어


Ascii Adjust for Addition
AAA : 덧셈후 10진 보정


Jump if Above
JA : 비교 결과가 크면 점프










AAD : 나누기전에 10진 보정
AAM : 곱한후 10진 보정
AAS : 뺄셈후 10진 보정
ADC : 더할때 carry 도 포함
ADD : 오른쪽에 왼쪽으로 더하기
CALL : 서브루틴을 호출
CBW : 바이트를 워드로 저장
CLD : 방향 플래그를 클리어
CLI : 인터럽트 플래그를 클리어
CMP : 오퍼랜드 비교하기

JAE : 크거나 같으면 점프


Jump if Below
JB : 비교 결과가 작으면 점프



JGE : 크거나 같으면 점프
JMP : 조건없이 점프
JLE : 작거나 같으면 점프


Jump if Not Greater or Equal
JNGE : 결과가 작으면 점프


Decimal Adjust for Addition
DAA : 덧셈후 AL 레지스터에 보정





DEC : 오퍼랜드 값에서 1을 뺌
DIVIDE : 나눗셈을 수행
IMUL : 곱셈을 수행
INC : 오퍼랜드 값을 1 증가시킴
INT : 인터럽트를 호출







MOV : 오퍼랜드에 값을 이동시킴
MUL : 곱하기
NOP : 3 사이클 동안 작동안함
POP : 스택에서 꺼냄
PUSH : 스택에 넣음
SUB : 나누기
XCHG : 두 오퍼랜드의 값을 서로 바꿈
실습 포인트
기초 명령어
사용법
- 10 -
어셈블리 - 기초 명령어(실습 포인트)
 EAX 레지스터에서 00ch 에 해당하는 값을 빼라.
 EBX 레지스터의 값이 81010100h 일때 00000004h 주소로 점프하라.
 서브루틴 00000007h 를 호출하라.
- 11 -
어셈블리 - 기초 명령어(문제 풀이)
 EAX 레지스터에서 00ch 에 해당하는 값을 빼는 법.

SUB
EAX, 00ch
 EBX 레지스터의 값이 81010100h 일때 00000004h 주소로 점프하라.


CMP
JZ
EBX, 81010100h
00000004h
실습 포인트
 서브루틴 00000007h 를 호출하라.

CALL
00000007h
기초 명령어
사용법
AT&T 방식
- 12 -
어셈블리 - 기초 명령어(실습 포인트)
 EAX 레지스터에서 00ch 에 해당하는 값을 AT&T 어셈블리 방식을 이용하여 빼라.
- 13 -
어셈블리 - 기초 명령어(문제 풀이)
 EAX 레지스터에서 00ch 에 해당하는 값을 AT&T 어셈블리 방식을 이용하여 빼는 법.

SUB
$0x00ch, %EAX
- 14 -
어셈블리 - 레지스터
 레지스터란 무엇인가 ?




레지스터는 수학적인 연산이 가능하다.
레지스터는 CPU 내에 내장되어 있다.
메모리는 읽고 쓰기는 가능하지만 연산은 불가능하다.
메모리의 느린 처리능력을 레지스터가 보강해 준다.
 레지스터의 종류





일반 레지스터(General Purpose Register)
포인터 레지스터(Pointer Register)
스택 레지스터(Stack Register)
플래그 레지스터(Flag Register)
세그먼트 레지스터(Segment Register)
- 15 -
어셈블리 - 일반 레지스터 1




eax
32비트중 오른쪽 16비트 = AX[왼쪽 상위 AH(8비트)+오른쪽 하위 AL(8비트)]
입출력과 산술연산에 사용
곱셈, 나눗셈, 변환 명령어






ebx
32비트중 오른쪽 16비트 = BX[왼쪽 상위 BH(8비트)+오른쪽 하위 BL(8비트)]
베이스 레지스터
주소지정용 인덱스로 사용
계산에 사용
특정주소 지정때 DI 나 SI 와 함께 사용




ecx
32비트중 오른쪽 16비트 = CX[왼쪽 상위 CH(8비트)+오른쪽 하위 CL(8비트)]
카운터 레지스터
루프횟수를 제어
• 32 비트
• 16 비트
- 16 -
어셈블리 - 일반 레지스터 2





edx
32비트중 오른쪽 16비트 = DX[왼쪽 상위 DH(8비트)+오른쪽 하위 DL(8비트)]
데이터 레지스터
일부 연산에서 반드시 edx 를 사용해야 한다.
큰수의 곱셈과 나눗셈 연산





si
16비트 원시 인덱스 레지스터 (source index register)
문자 연산에 사용
DS 와 함께 사용
ESI(80386 의 32비트 확장 레지스터)





di
16비트 목적지 인덱스 레지스터 (destination index register)
문자 연산에 사용
ES 와 함께 사용
EDI(80386 의 32비트 확장 레지스터)
• 32 비트
• 16 비트
- 17 -
어셈블리 - 세그먼트 레지스터
 CS(Code Segment)

코드를 저장
 DS(Data Segment)

테이터를 저장
 EX(Extra Segment)

스트리밍을 저장
 SS(Stack Segment)

리턴어드레스를 저장
- 18 -
어셈블리 - 인덱스 레지스터
 SI(Source Index)

문자열, 배열의 소스 인덱스를 저장.
 DI(Destination Index)

문자열, 배열의 목적지 인덱스를 저장.
 IP(Instruction Pointer)

차후 실행될 명령어의 주소를 저장.
- 19 -
어셈블리 - 스택 레지스터
 BP(Base Pointer)

실습 포인트
상위주소를 가리킴.
스택 관련
명령어
사용법
 SP(Stack Pointer)

하위 주소를 가리킴.
- 20 -
어셈블리 - 스택 레지스터 (실습 포인트)
 다음의 문제는 AT&T 어셈블리 방식을 적용하여 푼다.

베이스 포인터(Base Pointer) 의 값을 스택에 저장하라.

스택 포인터(Stack Pointer) BP 에 넣어 스택을 초기화 시켜라.
- 21 -
어셈블리 - 스택 레지스터 (문제 풀이)
 다음의 문제는 AT&T 어셈블리 방식을 적용하여 푼다.

베이스 포인터(Base Pointer) 의 값을 스택에 저장하기.
 push

%ebp
스택 포인터(Stack Pointer) BP 에 넣어 스택을 초기화 시켜라.
 movl
%esp, %ebp
- 22 -
어셈블리 - 기초 명령어 사용법


Ascii Adjust for Addition
AAA : 덧셈후 10진 보정










AAD : 나누기전에 10진 보정
AAM : 곱한후 10진 보정
AAS : 뺄셈후 10진 보정
ADC : 더할때 carry 도 포함
ADD : 오른쪽에 왼쪽으로 더하기
CALL : 서브루틴을 호출
CBW : 바이트를 워드로 저장
CLD : 방향 플래그를 클리어
CLI : 인터럽트 플래그를 클리어
CMP : 오퍼랜드 비교하기


Decimal Adjust for Addition
DAA : 덧셈후 AL 레지스터에 보정





DEC : 오퍼랜드 값에서 1을 뺌
DIVIDE : 나눗셈을 수행
IMUL : 곱셈을 수행
INC : 오퍼랜드 값을 1 증가시킴
INT : 인터럽트를 호출
실습 포인트
어셈블리
명령어
사용법
응용편


Jump if Above
JA : 비교 결과가 크면 점프

JAE : 크거나 같으면 점프


Jump if Below
JB : 비교 결과가 작으면 점프



JGE : 크거나 같으면 점프
JMP : 조건없이 점프
JLE : 작거나 같으면 점프


Jump if Not Greater or Equal
JNGE : 결과가 작으면 점프







MOV : 오퍼랜드에 값을 이동시킴
MUL : 곱하기
NOP : 3 사이클 동안 작동안함
POP : 스택에서 꺼냄
PUSH : 스택에 넣음
SUB : 나누기
XCHG : 두 오퍼랜드의 값을 서로 바꿈
- 23 -
어셈블리 - 기초 명령어 사용법 1(실습 포인트)
 ax 의값을 36h 으로 설정하여라.

 ax 의 값은 bx 주소값으로 대체하여라.
 dx 의 값을 36h 으로 설정하여라.

 dx 의 값을 증가 시켜라.

 dx 의 값을 감소 시켜라.
- 24 -
어셈블리 - 기초 명령어 사용법 2(문제 풀이)
 ax 의값을 36h 으로 설정하기.

mov
ax, 36h
 ax 의 값은 bx 주소값으로 대체하기.

mov
ax, bx
 dx 의 값을 36h 으로 설정하기.

mov
dx, 50h
 dx 의 값을 증가 시키기.

inc
dx <--- 37h(dx++)
 dx 의 값을 감소 시키기.

dec
dx <--- 35h(dx--)
- 25 -
어셈블리 - 기초 명령어 사용법 2(실습 포인트)
 ax 의값을 36h 으로 설정하여라.
 ax 의 값은 bx 주소값으로 대체하여라.
 dx 의 값을 36h 으로 설정하여라.
 dx 의 값을 증가 시켜라.
 dx 의 값을 감소 시켜라.
- 26 -
어셈블리 - 기초 명령어 사용법 2(문제 풀이)
 ax 의값을 36h 으로 설정하기.

mov
ax, 36h
 ax 의 값은 bx 주소값으로 대체하기.

mov
ax, bx
 dx 의 값을 36h 으로 설정하기.

mov
dx, 50h
 dx 의 값을 증가 시키기.

inc
dx <--- 37h(dx++)
 dx 의 값을 감소 시키기.

dec
dx <--- 35h(dx--)
- 27 -
어셈블리 - 기초 명령어 사용법 3

-
나중에 사용하기 위한 용도로 ax 에 임시로 값을 저장하라.
push ax
<-- 16비트 레지스터만 가능함.
다음의 예제에서 최종 ax 와 bx 의 값을 구하라.
실습 포인트

mov ax, 36h
<-- ax = 36h

mov bx, 2fh
<-- bx = 2fh



xchg ax, bx
<-- ax = 2fh, bx = 36h
push ax
<-- ax 의 값을 저장.

mov ax, 21h
<-- ax 의 값에 21h 를 대신 저장.

pop bx
<-- bx 의 원래값인 2fh 를 회복시킴.



push bx
<-- bx 의 값(2fh)를 저장.
pop ax
<-- ax 의 새로운 값인 21h 에서 원래값인 2fn 을 회복시킴.
어셈블리
명령어
사용법
응용편
- 28 -
어셈블리 - 기초 명령어 사용법 3(실습 포인트)
 다음의 dx 의 값과 ax 의 값을 교환하라.



mov
mov
dx, 36h
ax, 2fh
 참고
 xchg 사용시 8비트(h/l) 레지스터와 16비트(x) 레지스터는 절대 교환해서는 안된다.

xchg ah, bx <--- 8비트, 16비트가 같이 혼용 되어서는 안된다.
- 29 -
쉘코드 만들기(문제 풀이)
• 문자열을 넣고 주소를 계산한다.
• 계산된 문자열의 주소를 가리키는 주소를 레지스터에 넣는다.
- 30 -
쉘코드 만들기
실습 포인트
 쉘 실행코드란 무엇인가 ?
쉘실행 코드
만들기
쉘코드의 모습
 쉘을 실행하는 기능을 가진 짧은 코드를 의미한다.
 쉘코드로 변환되어 사용된다.
 execve(시스템 콜 번호 11) 와 setreuid(시스템 콜 번호 70) 의 함수가 필수적이다.
 execve() 콜은 /bin/sh 를 실행시킬때 사용된다.
 setreuid()콜은 suid root 프로그램에 보안상 설정된 일반사용자 권한을 루트권한으로 바꾸어 준다.
 쉘코드에서 이 권한을 복구하지 않으면 루트쉘이 아닌 일반쉘이 뜨기 때문에 반드시 복구해야 한다.
- 31 -
쉘코드 만들기(실습 포인트)
 쉘 실행코드를 제작한 후 어셈블과 링크과정을 거친 후 실행여부를 테스트 하라.
- 32 -
쉘코드 만들기(문제 풀이)
• 문자열을 넣고 주소를 계산한다.
• 계산된 문자열의 주소를 가리키는 주소를 레지스터에 넣는다.
- 33 -
쉘코드 만들기(문제 풀이)
 mov [ebx + 7], al 분석하기
 al 에 들어있는 내용을 ebx +7
레지스터 주소에 저장하라는 명령이다.
 32 비트 eax 레지스터 대신에 8비트 al 레지스터를 사용하여 eax 의 처음 1바이트 만을 사용하고 있다
 eax 의 처음 1 바이트를 문자열의 7번째 주소로 복사한다.
 ebx 에는 문자열 “/bin/shXAAAABBBB”에 대한 주소가 들어있다.
• 7번째 위치
- 34 -
쉘코드 만들기(문제 풀이)
 mov [ebx + 8], ebx 분석
 mov [ebx + 12], eax 분석
 32 비트(4바이트) 레지스터 하나를 통째로 사용하여 “AAAA” “BBBB” 부분에 값을 복사한다.
 “AAAA” 부분인 ebx + 8 에는 문자열의 주소(ebx)가 저장된다.
 “BBBB” 부분인 ebx + 12 에는 널주소인 0(eax) 이 저장된다.
- 35 -
쉘코드 만들기(문제 풀이)
 lea ecx, [ebx + 8]
 주소 읽기 명령인 lea 를 이용하여 소스메모리의 주소를 목적지에 저장한다.
 문자열의 “AAAA” 부분에 해당되는 주소를 ecx 에 넣는다.
 lea edx, [ebx + 12]
 주소 읽기 명령인 lea 를 이용하여 소스메모리의 주소를 목적지에 저장한다.

문자열의 “BBBB” 부분에 해당되는 주소를 edx 에 넣는다.
• 참고 : 주소값을 담고 있는 메모리의 주소값을 저장하는 이중법을 쓰는 이유는 execve() 함수가 마지막 2개의 인자를 받아들일때
포인터의 포인터 값으로 받아들이기 때문이다. 다시 말하면 인자의 값은 주소값을 담고 있느 메모리의 주소값이 되어야 한다.
- 36 -
쉘코드 만들기(문제 풀이)
 어셈블과 링크과정을 거친 후 실행하기.
 $ nasm -f elf shell.asm
 $ ld shell.o
 $ ./a.out
실습 포인트
루트 장악용
쉘실행 코드
만들기
- 37 -
쉘코드 만들기(실습 포인트)
 shell.asm 으로 생성된 a.out 를 루트 장악용 쉘실행코드로 변환하라.
- 38 -
쉘코드 만들기(문제 풀이)
 shell.asm 으로 생성된 a.out 를 루트 장악용 쉘실행코드로 변환하기.
 # chown root a.out
 # chmod +s a.out
 # exit
 $ ./a.out
- 39 -
쉘코드 만들기 - 단일 세그먼트에서 처리하기
 shell.asm 은 아직은 미완성된 쉘코드라고 볼 수 있다.
 쉘코드는 단독으로 작동할 수 없으며 공격대상 프로그램내에 삽입되어야 그 기능이 작동된다.
 데이터 세그먼트에 들어있는 문자열을 명령코드 쪽에 저장하고 그 주소를 찾아내는 것이 관건이다.
 문자열 주소는 명령어가 들어있는 주소와 같은 곳에 존재한다.
 쉘코드 실행시의 정확한 메모리주소를 알 수 없기 때문에 EIP 를 참조하여 찾아내야 한다.
 jmp 와 call 은 EIP 와 특정한 규칙관계를 가지고 있는 점을 이용한다.
 jmp 와 call 은 EIP 를 메모리의 특정한 곳으로 이동하도록 지시하는 기능을 가지고 있다.
 프로그램 시작 > call 명령과 문자열이 있는 코드의 끝으로 jump > call 명령 실행 >
문자열 주소가 스택에 삽입 > call 명령은 맨처음의 jump 명령 바로 다음위치로 제어를 이동 >
프로그램은 문자열 주소를 스택에서 꺼낸뒤 쉘코드를 실행
- 40 -
쉘코드 만들기 - 단일 세그먼트에서 처리하기
 프로그램 실행후 two 로 jump > 리턴주소(문자열 주소)를 스택에 삽입 > one 으로 이동 >
스택에서 문자열 주소를 꺼냄 > EBX 에 저장 > 쉘코드 실행
 jmp two
 one :
 pop ebx
 [프로그램 코드부분]
 two :
 call one
 db ‘예제에 사용되는 문자열’
 다음 페이지에서 위의 알고리즘을 처리하는 코드를 제공하니 참고하시기 바란다.
- 41 -
쉘코드 만들기 - 단일 세그먼트에서 처리하기
• shellcode_1.asm
- 42 -
쉘코드 만들기 - 널바이트 없애기
 개선된 코드 ‘shellcode_1.asm’을 헥사 편집기를 이용하여 분석한다.
 $ nasm shellcode_1.asm
 $ hexedit shellcode1
• ’00’ 으로 되어 있는 부분이 널바이트 이다.
• 문자열의 끝으로 인식하기 때문에 첫 2바이트만 버퍼에 복사한다.
• 쉘코드 모두를 버퍼로 복사하기 위해서는 모든 널바이트를 제거해야 한다.
- 43 -
쉘코드 만들기 - 널바이트 없애기
 ‘0’ 이라는 값을 사용하지 않고 레지스터에 ‘0’을 저장하기 위해서는 임의의 32 비트
값을 레지스터로 불러온 다음에 다시 그 값을 레지스터에 빼는 방법을 사용한다.
 이 방법은 용량이 늘어나기 때문에 쉘코드가 커진다는 단점을 가지고 있다.
 쉘코드는 실행의 특성상 되도록이면 용량을 작게 만드는 것이 좋은 방법이다.
 mov ebx, 0x11223344
 sub ebx, 0x11223344
- 44 -
쉘코드 만들기 - 널바이트 없애기
 레지스터와 그 레지스터 본인을 XOR 연산하게 되면 값이 ‘0’ 이 되기 때문에 널바이트
제거의 한 방법이 된다.
 OR 연산
 0 OR 0 = 0
 0 OR 1 = 1
 1 OR 0 = 1
 1 OR 1 = 1
 XOR 연산
• OR 연산과 XOR 연산의 차이점
 0 XOR 0 = 0
 0 XOR 1 = 1
 1 XOR 0 = 1
 1 XOR 1 = 0
- 45 -
쉘코드 만들기 - 단일 세그먼트에서 처리하기
• shellcode_2.asm
- 46 -
쉘코드 만들기 - 널바이트 없애기
 개선된 코드 ‘shellcode_2.asm’을 헥사 편집기를 이용하여 분석한다.
 $ nasm shellcode_2.asm
 $ hexedit shellcode2
• shellcode.1.asm 보다 널바이트가 줄어든 것을 확인할 수 있다.
- 47 -
쉘코드 만들기 - 널바이트 없애기
 어셈블된 기계어를 비교해 보면 다음과 같이 분석된다.
 mov eax, 70
=
B8 46 00 00 00
•0xB8 •0x00000046
 복사될 ’70’ 은 1바이트인데 32비트(4바이트) 레지스터의 특성상 3개의 널바이트가 생성된다.
 EAX 의 8비트 레지스터인 AL 을 사용하여 널바이트를 제거할 수 있다.
• shellcode.1.asm 보다 널바이트가 줄어든 것을 확인할 수 있다.
- 48 -
쉘코드 만들기 - 널바이트 없애기
 다음과 같이 EAX 대신 AL 을 사용하여 널바이트를 제거한다.
 mov al, 70 ; = B0 46
 위 같은 방식에서는 처음 1바이트만이 ‘0’으로 바뀌고 나머지는 바뀌지 않기 때문에
다음과 같이 레지스터 전체를 ‘0’으로 바꾸고 난후 다음 1바이트를 AL 로 복사하면 된다.
 xor eax, eax ; 반드시 다음 명령을 위해 eax 를 0 으로 설정해야만 한다.
 mov al, 70 ;
- 49 -
쉘코드 만들기 - 널바이트 없애기
• Shellcode.asm
- 50 -
쉘코드 만들기 - 널바이트 없애기
 다시 개선된 코드 ‘shellcode.asm’을 헥사 편집기를 이용하여 분석한다.
 $ nasm shellcode.asm
 $ hexedit shellcode
• 널바이트 모두 제거된 것을 확인할 수 있다.
• 쉘코드의 크기도 줄어든 것을 확인할 수 있다.
- 51 -
쉘코드 만들기 - 널바이트 없애기
 XAAAABBBB 의 목적은 널바이트와 2개의 주소에 대한 메모리 할당을 위해서 입력되었다.
 쉘코드를 단독 개별 프로그램으로 제작했을 때는 위의 인자가 필요하다.
 쉘코드가 다른 프로그램이 만든 메모리에 삽입될때는 위의 인자가 필요없다.
 그렇기 때문에 ‘XAAAABBBB ‘ 를 제거하여 쉘코드의 크기를 줄일 수 있다.
- 52 -
쉘코드 만들기 - 널바이트 없애기
 최종적인 코드 ‘shellcode.최종.asm’을 헥사 편집기를 이용하여 분석한다.
 $ nasm shellcode.최종.asm
 $ hexedit shellcode.최종
• 코드의 크기가 더욱 줄어든 것을 확인할 수 있다.
- 53 -
쉘코드 만들기 - 바이트 코드 만들기
 바이트 코드란 다음과 같은 형태를 가진 코드를 의미한다.
 쉘코드란 다음과 같은 형태를 가진 코드를 의미한다.
- 54 -
쉘코드 만들기 - 바이트 코드 만들기
바이트 코드를 제작하기 위한 도구로써 다음과 같은 것들이 사용된다.
 gcc
 nasm
 ld
 objdump
 ndisasm
- 55 -
쉘코드 만들기 - 바이트 코드 만들기
 완성된 쉘코드용 asm 소스를 이용하여 바이트 코드와 쉘코드 제작하기
 바이트 코드란 무엇인가 ?
• 널바이트와 문자열을 제거하여 크기가 축소된 산뜻한 asm 코드를 만든 후에는 최종적으로
바이트 코드를 제작하는 단계로 들어간다.
즉 여러분들이 자주 보던 공격코드(exploits) 에 들어 있는 다음과 같이 생긴 것들을 일컬어
바이트 코드라고 부르는 것이다.
• 바이트 코드의 모습
- 56 -
쉘코드 만들기 - 바이트 코드 만들기
 그렇다면 쉘코드는 또 무엇인가 ?

쉘코드는 바이트 코드를 프로그램 내에 삽입하여 실행 가능하게 만든 완전한 형태의 코드를
뜻한다. 즉, 바이트 코드를 실행하려면 조금 더 마무리 작업을 해주어야 하겠지요 ? 그렇지
않고 저기 보이는 저런 발가벗은 형태의 바이트 코드가 혼자서는 제 역할을 해낼 수가
없지요 ?
• 이것을 다음과 같이 완전한 형태로 만들어 준 것을 쉘코드라고 합니다. 즉 프로그램내에
삽입되어 제 구실을 하게끔 프로그래밍 문법을 적용시킨 것이라고 보시면 됩니다.
• 그림을 보시면 ‘\x69\x6e……” 되어 있는 바이트 코드 앞에 ‘char
hellc0de….어쩌구..저쩌구’ 와 같은 코드를 추가해준 것입니다.
• 쉘코드의 모습
- 57 -
쉘코드 만들기 - 바이트 코드 만들기
 바이트 코드를 만들기 위한 준비물
• gcc
• nasm
• ld
• objdump
• ndisasm
- 58 -
쉘코드 만들기 - 바이트 코드 만들기
 바이트 코드 삽입 후 실행 유무 테스트용 본체
- 59 -
쉘코드 만들기 - 바이트 코드 만들기
 exit.asm 코드를 바이트 코드로 만들기
소스코드
;exit.asm
[SECTION .text]
global _start
_start:
xor eax, eax
;exit is syscall 1
mov al, 1
;exit is syscall 1
xor ebx,ebx
;zero out ebx
int 0x80
- 60 -
쉘코드 만들기 - 바이트 코드 만들기
 명령어 사용법
•nasm -f elf exit.asm
•ld -o exiter exit.o
•objdump -d exiter
 결과물
- 61 -
쉘코드 만들기 - 바이트 코드 만들기
 결과물에서 산출한 바이트 코드
•b0 01 31 db cd 80
 산출된 바이트 코드를 쉘코드 형태로 변환하기
•char shellcode[] = "\xb0\x01\x31\xdb\xcd\x80";
 프로그램 본체에 삽입된 쉘코드의 완전한 모습
- 62 -
쉘코드 만들기 - 바이트 코드 만들기

hello.asm 을 바이트 코드로 만들고 출력하기
소스코드
• ;hello.asm
• [SECTION .text]
• global _start
• _start:
•
jmp short ender
•
starter:
•
xor eax, eax
•
xor ebx, ebx
•
xor edx, edx
•
xor ecx, ecx
•
mov al, 4
;syscall write
•
mov bl, 1
;stdout is 1
•
pop ecx
;get the address of the string from the stack
•
mov dl, 5
;length of the string
•
int 0x80
•
xor eax, eax
•
mov al, 1
•
xor ebx,ebx
•
int 0x80
•
ender:
•
call starter
•
db 'hello'
;clean up the registers
;exit the shellcode
;put the address of the string on the stack
- 63 -
어셈블리 - 기초 명령어 사용법 3(문제 풀이)
 다음의 dx 의 값과 ax 의 값을 교환하는 법.



mov
mov
xchg
dx, 36h
ax, 2fh
dx, ax
- 64 -