60바이트 크기의 MINI60
이 분석할 악성코드 파일이다.
지난 글에서 사용한 debug
툴로 MINI60
파일을 열어보자.
우선 분석을 시작하기 전에 SI
레지스터를 0x100
로 이동시켜야 한다. MINI60
이라는 악성코드 자체의 확장자가 원래 .com
파일이고, .com
파일의 기본 SI
는 0x100
이기 때문이다.
코드를 한줄 한줄 실행시켜가면서 분석해보자.
코드를 실행시키다보니 INT 21
, 인터럽트를 실행시키는 코드가 등장했다. 이전 글에서 언급했듯이 INT
는 AH
레지스터의 값으로 종류를 구분하기 때문에 INT 21,4E
에 대해 찾아보자.
뭔가 조건에 맞는 첫 번째 파일을 찾는 인터럽트처럼 보인다. DX
레지스터에 저장된 값을 와일드카드를 포함한 아스키 파일 규격의 포인터로 사용하는 것 같다. 즉, 해당 레지스터에 저장된 값이 일종의 파일 이름 정규표현식 역할을 하는 것이다. 어떤 파일을 찾는지 확인해보자.
*.*
즉, 모든 파일 형식을 찾는 것을 알 수 있다.
파일을 찾는 데 실패하면 캐리 플래그가 SET
되며 AX
레지스터에 에러코드를 반환하고, 파일을 찾는 데 성공하면 DTA
라는 구조로 해당 파일의 정보를 반환하는 것 같다.
DTA
의 구조를 살펴보자.
기본적으로 DTA
의 오프셋은 0x80
이고, 해당 오프셋으로부터 Ox1E
번째 오프셋에 찾고자 하는 파일의 이름이 존재하는 것 같다. 그렇다면 0x9E
오프셋에 해당 파일 이름이 존재하는 것이기 때문에 해당 주소의 값을 살펴보자.
MIN60
폴더 내부의 MINI60
악성코드를 제외한 1234
라는 이름의 파일을 찾아낸 것을 볼 수 있다. Ox9A
에는 해당 파일의 사이즈도 저장되어 있는 것 같으니 확인해보자.
실제로 1234
파일은 5바이트짜리 파일이기 때문에 정상적으로 잘 저장이 된 것을 확인할 수 있다.
지금까지 악성코드의 실행 방식은 해당 폴더 내부에서 *.*
형식에 알맞은 첫 번째 파일을 찾는 것이다.
또다시 인터럽트가 등장했다. 이번엔 INT 21,3D
를 찾아보자.
이번엔 핸들을 이용해서 해당 파일을 오픈하는 인터럽트인 것 같다. 현재 AL
이 0x02
이므로 읽기 및 쓰기 모드로 연 것을 알 수 있고, DX
에는 0x9E
즉, 아까 확인했던 읽어온 파일의 이름이 들어가는 것을 볼 수 있다. 파일을 여는 데 성공한다면 AX
에 해당 파일의 핸들을 리턴해주고 캐리 플래그가 set
되지 않는다.
캐리 플래그가 발생하지 않을 것으로 보아 파일을 여는 데 성공했고, AX
에 저장된 0x5
는 해당 파일의 핸들임을 알 수 있다.
이번엔 INT 21,3F
이다.
핸들을 이용해 파일이나 장치를 읽는 인터럽트같다.
BX
에 저장된 값을 파일 핸들로, CX
에 저장된 값을 읽어올 바이트 수로, DX
에 저장된 값을 읽어올 버퍼의 포인터로 사용한다. 현재 CX
에는 OxFD
가 저장되어 있는데, 이는 크게 의미있는 수치가 아니라 이 악성코드 제작자가 악성코드의 길이를 정확히 60바이트로 맞추려다보니 작성한 코드라고한다. DX
에는 0x13C
, 즉 메모리의 시작점부터 해당 악성코드가 차지하는 부분 바로 다음의 주소이다.
만약 파일을 읽는 데 성공한다면 읽어온 바이트 수를 AX
에 리턴해주고 캐리를 발생시키지 않는다.
캐리가 여전히 NC
인 것으로 보아 파일을 읽는 데 성공했고 읽어온 바이트 수는 5바이트인 것으로 보인다. 이 때, AX
와 BX
모두 0x5
라는 값이 들어있지만, AX
에 들어있는 값은 읽어온 바이트 수, BX
에 들어있는 값은 파일의 핸들이다.
현재까지 이 악성코드는 감염시킬 파일을 찾고, 해당 파일의 정보를 메모리 상에서 자신이 차지하는 부분 바로 다음에 위치시키는 작용을 한다. 읽어온 부분의 데이터를 확인해보자.
1234
파일의 내용인VIRUS
를 잘 읽어온 것을 볼 수 있다.
다음에 실행하는 코드가 좀 특이한데, 읽어온 파일의 첫 부분이 0x2A
로 시작하는지 검사한다. 이 악성코드 자체의 작용 메커니즘이 자가 복제 매커니즘이기 때문에 읽어온 파일이 이미 감염되었는지 확인하는 절차인 것이다. 중복 감염을 방지하는 로직이다.
이 부분에서 재밌는 부분이 나오는데, 우선 CX
레지스터의 값을 XOR
연산을 이용해 초기화시킨 후, MUL
명령을 실핸하는데 MUL
명령은 AX
레지스터와 MUL
의 첫 번째 오퍼랜드를 곱한 후 AX
와 DX
에 나눠서 저장하는 명령이다. 악성코드 작성자는 2바이트의 XOR
과 2바이트의 MUL
로 세 개의 레지스터를 모두 0으로 초기화시킨 것이다.
또 다시 인터럽트이다. INT 21,42
를 확인해보자.
파일 포인터를 이동시키는 인터럽트이다. 파일을 읽어올 때 파일 포인터가 파일의 맨 끝으로 이동했기 때문에 해당 파일의 포인터를 맨 앞에 위치시켜 주는것이다.
INT 21,40
을 살펴보자.
DX
에 저장된 값의 주소부터 CX
에 저장된 값의 바이트 수 만큼 BX
파일 핸들에 쓰는 인터럽트이다.
지금까지 이 악성코드의 작동 원리는 우선 *.*
의 형식의 파일을 찾고, 해당 파일을 열어서 메모리 상 자신의 다음에 위치시킨 후, 중복 감염 여부를 조사하고 감염된 파일이 아니라면 파일 포인터를 파일의 맨 앞으로 이동시킨 후 DX
에 저장된 값의 주소부터 CX
에 저장된 값의 바이트 수 만큼 파일에 쓰는 원리이다.
이전의 파일을 성공적으로 감염시켰으니 조건에 맞는 다음 파일을 찾는 인터럽트를 실행한다.
다음에 찾은 파일을 확인해보니 0x9E
에 자기 자신이 들어있는 모습을 볼 수 있다. 그렇다면 자기자신은 중복 감염 여부를 검사하는 로직에서 뭔가 다르게 작용할 것이다. 확인해보자.
Zero
플래그가 SET
되어 0x138
로 점프한 것을 볼 수 있다.
이후 또 다시 다음 파일을 찾지만, 해당 폴더에 더 이상 파일이 없기 때문에 캐리 플래그가 발생하고 AX
레지스터에 에러코드가 리턴된 것을 볼 수 있다. 해당 에러코드를 살펴보자.
DOS
에러코드에서 12는 NO more files
, 즉 찾을 파일이 더 이상 없다는 것을 의미한다.
해당 악성코드는 같은 폴더 내의 *.*
형식의 파일을 찾아 열어서 메모리 상에서 자신이 위치하는 다음 부분에 불러온 후 해당 파일의 첫부분을 검사해 중복 감염을 방지하고 감염된 파일이 아니라면 파일 포인터를 처음으로 이동시킨 후 자기 자신+해당 파일의 내용을 파일에 새로 써내서 복제하는 악성코드이다.
1234
파일의 크기가 60 + 5, 65바이트로 증가했고 내부를 살펴보면
자기자신을 복제한 후 뒤에 해당 파일의 내용을 붙이는 식으로 감염시켰음을 알 수 있다. 해당 파일의 치료는 원래 파일의 내용 앞부분을 지우면 정상적으로 치료가 된다.
이렇게 수정하면 치료가 완료된 것이다.