취약점분석/Reversing

[Reversing] 바이러스의 보안 모듈 우회 방법

poiri3r 2025. 6. 11. 13:34

백신은 사용자에게 악의적인 피해를 끼치는 경우에만 바이러스로 규명하지 않고, 사용자가 악의적인 행동을 할 가능성이 있는 모든 바이너리를 악성코드로 진단한다. 

 

백신의 기본적인 탐지 원리

시그니처(패턴) 기반 탐지

악성코드의 고유한 코드 조각(시그니처)를 백신의 데이터베이스에 저장해 두고, 검사 대상이 시그니처와 일치하는지 비교해서 탐지하는 방식이다.

시그니처의 종류로는

1. 바이너리 패턴

2. 파일 해쉬값

3. 특정 API 호출 조합이 있다.

시그니처 기반 탐지는 알려진 악성코드는 거의 100%탐지가 가능해서 정확도가 높고 시스템 자원을 적게 소모해 빠르다는 장점이 있지만, 신종 악성코드는 탐지 할 수 없고 우회가 쉽다는 단점이 있다.

 

고전적인 우회 방법

 

1. 리빌드

변수를 몇 개 추가하고 함수의 위치를 바꾸는 식으로 코드만 조금 변형해서 리빌드하면 기존 패턴과 바이너리 값이 바껴서 시그니처 기반 탐지를 우회할 수 있다.

예를 들어, 백신에서 [0x75 0x17 0x50 0x68 0xB4]를 악성코드의 시그니처로 가지고 있을때 리빌드 과정을 걸쳐서 바이러스의 바이너리 값이 [0x75 0x17 0x50 0x68 0xB5]로 바뀐다면 백신 우회가 가능해진다.

▶다만 백신 엔진이 구식이던 시절에만 가능했던 우회 방법이다.

 

2.쓰레기 코드를 통한 우회

프로그램의 가동에 영향을 주지 않으면서 바이너리의 체크섬과 시그니처가 바뀔 수 있는 코드를 주입하는 방식으로, 

 

_asm

{

    push rbx     <-0x53

    inc rbx        <-0x43

    dec rbx       <-0x4B

    pop rbx       <-0x5B

}

 

과 같은 코드가 메모리에서 실행될 때 네 줄이 수행되고 나서도 아무것도 변경되지 않는다. 

또 백신이 가진 시그니처에서 쓰레기 코드의 바이너리 값인 [0x53 0x43 0x4B 0x5B]가 추가되면 바이너리 값이 달라졌기 때문에 백신은 바이러스로 진단하지 않는다.

(*쓰레기 코드는 대칭적인 구조를 가져야 한다.)

가장 기초적인 코드 진행은 되지만 아무 영향을 끼치지 않는 경우

3.실행조차 되지 않는 쓰레기 코드

쓰레기 코드의 유형 중 코드 진행에 영향을 주지 않는 경우도 있지만 jmp문을 활용하여 코드 진행을 아예 하지 않는 경우이다.

이러한 방식은 원본 프로그램에는 전혀 영향을 주지 않으면서 바이너리의 시그니철르 달라지게 할 수 있고, 분석하는 사람들에게 난독화의 효과도 줄 수 있다.

중국에는 쓰레기 코드 주입을 자동화 해주는 툴도 존재한다!

 

4.헤더 변조

일부 백신은 PE헤더 영역만 따로 검사하는 기능이 있어서 헤더의 내용만 바꾸면 감지하지 못하는 경우가 있다.

다만 PE 헤더는 쓰레기 코드를 주입하는 것은 불가능하므로 속성을 바꾸는데, 보통은 건드려도 영향이 없는 필드(ex. File Header의 TimeDateStamp, Optional Header의 CheckSum 등) 혹은 메모리 속성에 쓰기 권한을 추가하는 방법까지 다양하다.

하지만 최근 백신은 단순히 PE헤더만 보는것이 아니라 행동 기반 탐지, 머신러닝, 시뮬레이션 실행까지 같이 하므로 PE헤더만 변조해도 실행시 악성 행동이 나타나면 결국 탐지되어 다른 우회기법과 조합하여 사용한다.

 

5.문자열 패턴 우회

문자열을 XOR을 이용하여 파일상에서는 암호화하고 실행할 때 풀어내는 방법을 백신(시그니처 기반 탐지의 구형백신)을 피할 수 있다. 

 

아래는 대칭키 알고리즘을 이용한 XOR 루틴이다.

_asm

{

    pushad

    mov ebx,string

    mov ecx,4 

    mov eax, dword ptr[ebx]

    xor eax, 11223344

    mov dword ptr[ebx], eax

    add ebx, 4

    loopd short 0x40311E

    popad

    jmp OriginalEntry

}

먼저, 악성코드 입장에서 시그니처 스캔을 우회하기 위해 백신에 감지되는 문자열을 암호화 로직을 이용해 암호화 해둔다. 그러면 헥스 값 상에서도 문자열로 보이지 않고, 이상한 값으로 변환된 채로 파일상에 저장될 것이고 백신에 진단되지 않게 된다.

하지만 만약에 이대로 프로그램이 실행되면 원하는 문자열이 제대로 출력되지 않을 것이고, 크래시가 발생할 수도 있다. 따라서 실행 직전 원상복구하는 복호화 루틴이 필요한데, 여기서 PE헤더의 EP값을 이용해서 복호화루틴을 만들 수 있다.

아까 작성해둔 대칭키 알고리즘을 이용한 XOR 루틴을 0x4030E0(예시)에 추가해두고, PE헤더의 EntryPoint값을 조정하여 0x30E0값을 넣어둔다. 그리고 마지막에 [jmp OriginalEntry]를 통해 원래 EP값으로 jmp할 수 있게 수정을 해두면, 파일이 실행될 때 문자열을 복호화한 뒤에 다시 EP로 들어가게 된다.

6.패킹을 통한 우회

바이너리가 패킹되면 파일의 내용이 변경되므로 백신이 일차원적으로 스캔했을때는 시그니처가 있더라도 악성코드를 진단하지 못하게 된다. 하지만 백신 엔진이 개량되어 패킹된 파이너리를 풀어내는 작업을 하거나, 행동 기반 탐지 등을 통해 진단하므로 최근에는 패킹 그 자체만으로는 백신 프로그램을 우회하기 힘들다.

패커마다 고유한 암복호화 알고리즘이 있고, 특성 백신의 경우는 이러한 패커들의 규칙성을 판별해 어떤 패킹툴로 패킹됐는지 확인하고 그에 맞는 언패킹 알고리즘을 발효시킨다. 

이 때 언패킹후 바이너리를 숨기기 위해 다단계 패킹을 사용하기도 한다.

 

또한 백신 입장에서 타깃 바이너리 스캔을 할 때 어떤 패커로 패킹되어 있는지 검사하는 방법 중 섹션 이름을 조사해서 패커종류를 확인하는 방법이 있는데

사진처럼 UPX 패킹된 파일은 섹션 이름을 UPX로 가지기 때문에 섹션 이름만 조사해도 패킹된 파일임을 알 수 있다.

따라서 섹션 이름을 변경하는 것만으로도 삼류 백신에게 우회가 가능하다.

 

이상으로 바이러스의 보안 모듈 우회할 때 사용하는 고전적이면서 간단한 방법들에 대한 포스팅을 마치겠습니다!

다음엔 더 좋고 최신정보들로 포스팅 하도록 하겠습니다!

*이 포스팅은 리버스 엔지니어링 바이블 책을 참고하여 작성되었습니다.