Trawling

Sem86, 실험용 악성코드가 에뮬레이터 판별에 쓴 IMUL 명령 찾아냈다

Sem86은 x86 명령어 의미를 실행 중 데이터 파일에서 바꿔 적용하는 전체 시스템 에뮬레이터입니다. 저자들은 정의되지 않은 IMUL 뒤 제로 플래그(ZF) 처리를 달리한 실험용 악성코드의 화면 출력을 이분 탐색해 에뮬레이터 판별에 쓰인 명령을 찾았습니다. 명령어 의미는 현재 수작업으로 작성하며, libLISA를 통한 자동 추론은 장기 목표입니다.

2026년 7월 22~25일 이탈리아 피렌체에서 열린 QRS 2026에서 Jos Craaijo, Freek Verbeek, Binoy Ravindran은 libLISA의 Sem86을 발표했습니다. Sem86은 x86 명령어 의미를 에뮬레이터 코드에 고정하지 않고 실행 때 데이터 파일에서 불러오는 전체 시스템 에뮬레이터입니다. 저자들은 실험용 악성코드 예제로 IMUL 뒤 정의되지 않은 플래그 처리를 달리해, 에뮬레이터 판별에 쓰인 명령을 이분 탐색으로 찾았습니다.

명령어 의미를 파일에서 불러옵니다

전체 시스템 에뮬레이터는 CPU 명령어뿐 아니라 운영체제 구동에 필요한 장치와 주변 환경도 재현합니다. Sem86에서는 사용자가 semgen으로 x86 명령어 의미 파일을 만든 뒤 BIOS와 디스크 이미지를 지정해 운영체제를 부팅합니다. 저자들은 Windows 98, Windows XP, Windows 7을 부팅했고, 프로젝트 페이지는 Debian 8 실행도 소개합니다.

파일에서 읽어오는 것은 명령어 의미입니다. 실행 루프, 페이징, 제어 레지스터, 인터럽트 처리와 시스템 하드웨어는 에뮬레이터 코드에 구현돼 있습니다. 각 명령어 의미를 LLVM IR로 바꿔 실행 함수로 컴파일한 뒤 캐시하며, 자주 실행하는 코드 구간은 LLVM으로 JIT 컴파일해 실행합니다. 이 구조에서는 명령어 동작을 바꾸면서도 운영체제 부팅에 필요한 장치 모델과 실행 기반을 공통으로 사용할 수 있습니다.

현재 Sem86의 명령어 의미는 수작업으로 작성됐습니다. libLISA에는 16비트·32비트 x86 CPU를 관측하는 기능이 없어 해당 CPU의 명령어 의미를 자동 추론하지 못합니다. libLISA에서 CPU별 명령어 의미를 추론해 특정 CPU의 동작을 복제하는 일은 저자들이 밝힌 장기 목표입니다.

화면 출력으로 실행 지점을 찾습니다

일부 x86 명령어는 특정 플래그의 값을 규정하지 않습니다. CPU와 에뮬레이터가 그 값을 다르게 처리하면 프로그램이 그 차이를 이용해 실행 환경이 에뮬레이터인지 판별할 수 있다고 논문은 설명합니다. 저자들은 이를 보이기 위해 Windows 98용 작은 예제 악성코드를 직접 만들었습니다.

예제는 XOR 연산으로 ZF를 0으로 만든 뒤 IMUL로 15와 0을 곱하고, 이어 ZF를 검사합니다. IMUL 뒤 ZF 값은 정의되지 않습니다. 저자들은 두 가지 의미 파일을 준비했습니다. 하나는 Bochs처럼 곱셈 결과가 0이면 ZF를 1로 설정하고, 다른 하나는 IMUL이 ZF를 바꾸지 않아 앞서 설정한 0을 유지합니다. 논문은 최신 CPU에서 처리 양상이 다양하다고 설명하면서, 이 실험에서는 실제 CPU가 ZF를 바꾸지 않는 경우를 가정했습니다.

두 의미 파일은 프로그램의 분기와 화면 출력을 바꿉니다. Bochs 방식에서는 ZF가 1이 돼 “Analysis attempt detected”라는 메시지를 표시합니다. ZF가 0으로 유지되면 다른 분기를 타고 “Deleting C drive”라는 메시지를 띄웁니다. 이 문구는 예제가 표시한 메시지이며, 시연에서 달라진 결과는 실제 파일 삭제가 아니라 두 분기의 화면 출력입니다.

Sem86은 실행 중 명령어 의미를 바꾸고, 실행 횟수의 범위를 좁혀 결과가 달라지는 지점을 찾습니다. 저자들은 예제가 부팅 때 자동 실행되도록 설정하고, 4억 개 명령을 실행한 뒤의 화면 출력을 판별 기준으로 삼았습니다. 이분 탐색으로 두 결과를 갈라놓은 명령이 IMUL이라고 식별했습니다.

수억 개 명령을 탐색할 때 운영체제를 매번 처음부터 부팅하면 시간이 오래 걸립니다. Sem86은 CPU와 메모리, 하드웨어 상태를 스냅샷으로 저장했다가 불러와 그 지점부터 실행을 재개합니다. 논문은 파일 시스템 변화나 네트워크 접근도 실제 악성코드 분석에서 판별 기준으로 삼을 수 있다고 설명하지만, 이번 시연은 화면 출력을 기준으로 만든 예제입니다.

Sem86 저장소의 README는 프로젝트를 연구용으로 소개하며, 운영 환경에 사용할 준비가 되지 않았다고 밝힙니다. 현재 실행 환경은 Linux와 Android입니다. 사용자는 디스크 이미지를 따로 준비해야 하며, 기본 디스크 방식은 변경 사항을 메모리에 저장합니다. 소스 코드는 AGPLv3으로 공개돼 있습니다.

참고 자료

오류 제보