반응형

 

patched_ReverseMe Tutorial.exe
0.00MB

 

주제 - Diversion code, encryption/decryption, selfmodifying code and polymorphism

 


분석 1

 

 

 

2byte를 패치하여 Nag를 지워야 한다.

 

위의 사진에 보이는 창이 Nag 창이다.

 

위의 창을 없애야 한다.

 

 

 

위의 창은 main 창이다.

 


분석 2

 

 

EP 코드 부분이다.

 

4012BD 주소에서 MessageBoxA 함수를 호출하는데 인자로 2byte를 패치해서 Nag를 없애라는 문자열이 있다.

 

4012AF 주소부터 4012BB 주소까지가 4012BD 주소에서 호출하는 MessageBoxA 함수의 인자 부분이므로 4012AF 주소에 BP를 걸어준다.

 

그리고 MessageBoxA() 함수 부분에서 BP를 걸어주고 F9 키를 눌러 실행한다.

 

 

그러면 위와 같이 2byte를 패치해서 Nag를 없애라는 창이 뜬다.

 

BP를 걸었는데 BP가 무시되고 실행된 것이다.

 

EIP도 401288 주소로 되어있다.

 

 

BP를 걸어둔 4012AF 주소에서 멈추지 않은 이유는 BP를 건 주소 부분이 diversion(decoy) code이기 때문이다.

 

위의 사진에서 4012AF 주소부터 스택에 인자값들을 넣고 4012BD 주소에서 MessageBoxA() 함수를 호출하는데 이 부분이 우회 코드이다.

 

우회 코드란 리버싱 경험이 별로 없는 사람들을 속이기 위해서 특별히 생성된 코드이다.

 

이 우회 코드는 절대 실행되지 않기 때문에 BP를 걸어도 멈추지 않았던 것이다.

 

이번 강의에서 우회 코드를 넣어둔 이유는 리버싱을 할 때 문자열 검색을 통해 나온 결과를 100% 믿지 말라는 것이다.

 

4012AF 주소와 4012BD 주소에 걸어둔 BP를 제거하고 Ctrl + F2 키를 눌러 재실행 후 F8 키로 하나하나 따라간다.

 

 

40128A 주소에서 GetModuleHandleA() 함수를 호출한 뒤 반환값이 eax에 담기는데 400000 이라는 값이 들어있다.

 

이 400000 값은 403130 주소에 저장하고, edi 레지스터에 401011주소를 저장한 다음 40130F 주소의 함수를 호출한다.

 

 

40130F 주소는 스크롤을 조금 내리면 위와 같이 있다.

 

 

40130F 주소의 함수에서는 401000 주소를 eax에 저장하는데 401000 주소는 메모리 맵에서 봤을 때 위의 사진처럼 .text 섹션의 시작 주소이다.

 

그렇다면 40130F 주소의 함수를 호출하기 전 수행했던 GetModuleHandleA 함수도 우회 코드라고 유추할 수 있다.

 

 

401000 주소에 있는 1byte 데이터를 5A와 xor 연산하고, eax의 값을 1 증가한 뒤 BeginPaint() 함수로 점프하는 명령어가 있는 주소와 비교한다.

 

위의 3번째 사진을 보면 BeginPaint() 함수로 점프하는 명령어가 있는 주소는 401218이다.

 

증가된 eax의 값이 401218보다 작은 동안 40131D 주소에서 401314 주소로 점프하여 5A와 xor 연산을 한다.

 

401314 주소부터 40131D 주소까지가 401000 주소 ~ 401218 주소에 있는 암호화 된 바이트 코드를 대상으로 xor 연산으로 복호화 하는 루프이고, 이 루프를 Decrypting 루프라고 한다.

 

xor 연산의 특성은 아래와 같다.

A ^ B = C

B ^ C = A

 

즉, 암호화가 된 코드에 암호화 할 때 사용한 값을 xor 연산하면 복호화 된 값이 나오게 된다.

(encrypting xor이라고 하며 줄여서 enxor이라고도 한다.)

 

암호화 되어 있는 401000 ~ 401218
복호화 된 401000 ~ 401218

 

위의 두 개의 사진은 같은 주소의 코드인데 암호화 된 코드와 xor 연산으로 복호화 된 코드이다.

 

분석 하기 전에

 

self-modifying(자가 변조) 코드라고 부르는 코드가 있는데

 

자가 변조 코드는 컴퓨터를 사용하기 시작한 초창기 시절에 제한된 메모리 공간을 절약하기 위해 사용했다.

 

요즘은 바이러스나 쉘 코드처럼 특정 프로그램들이 자신의 존재를 숨기기 위해 자가 변조 코드를 사용하기도 하는데

 

자가 변조 코드를 사용하는 바이러스나 쉘 코드는 자가 변조 코드와 더불어 다형성 코드를 사용하기도 한다.

 

다형성 바이러스는 원시적 자가 변조 바이러스라고도 불리우며, 현재 실행되고 있는 코드를 변조하는 것은 시스템 공격에도 사용되기도 하는데 Buffer OverFlow가 대표적인 예시이다.

 

그렇기 때문에 리버싱을 하는 사람들을 난독화된 코드를 어떻게 분석해야 하는지를 알아야 한다.

 

암호화 되어 있는 401000 주소
복호화 된 401000 주소

 

40130F 주소의 함수에서 401000 ~ 401218 영역의 암호화 된 코드를 복호화 하면 위와 같이 변경된다.

 

그리고 40130F 주소의 함수가 끝나면 

 

 

40129E 주소로 점프한다.

 

40129E 주소에서 호출하는 401011 주소의 함수를 분석하기 위해 F7 키를 눌러 401011 주소의 함수 내부로 들어간다.

(401011 주소의 함수 내부로 가기 전에 edi 레지스터에 401011 주소를 저장했는데 40130F 주소의 함수에서는 사용하지 않았다.)

 

 

401011 주소의 내부는 위와 같은데 EDI 레지스터에는 401011 주소가 저장되어 있다.

 

401018 ~ 401052 주소까지 edi 레지스터가 여러번 사용되고

401072 ~ 4010B4 주소 역시 edi 레지스터가 여러번 사용된다.

 

 

위의 코드를 F8 키로 하나씩 따라간다.

 

먼저, xor 연산으로 eax 레지스터의 값을 0으로 초기화하고, edi 레지스터에는 401011 주소가 담겨있는데 401011 주소에서 2byte 데이터에 6A를 저장한다.

 

 

401013 주소의 mov 명령어가 수행되면 edi 레지스터에는 401011 주소가 담겨있으므로 401011 주소로부터 2byte 값을 6A로 바꾸어 위와 같이 xor 명령어에서 push 명령어로 바뀐다.

 

 

그리고 edi 레지스터 값에 2를 더함으로써 edi 레지스터에는 401013 주소가 담겨있게 된다.

 

 

edi 레지스터에 401013 주소가 담겨있는 상태에서 40101B 주소의 mov 명령어가 수행되면 401013 주소명령어는 mov 명령어에서 push 명령어로 바뀌게 된다.

 

40101B 주소의 mov 명령어에서 4byte 값을 수행했기 때문에 401021 주소에서는 edi 레지스터에 담긴 값에 4를 더한다.

 

이런식으로 401011 주소의 함수에서는 2차적인 복호화 작업을 수행한다.

 

 

40104F 주소까지 F8 키를 눌러 복호화 작업이 끝난 후 401052, 401054, 401059 주소에서 어떠한 함수들을 호출하는데

 

F7 키를 눌러 401052 주소에서 호출하는 함수 내부로 들어간다.

 

 

401052 주소에서 호출하는 함수 내부로 들어가면 위와 같이 401000 주소로 온다.

 

해당 주소는 .text 섹션의 시작 주소로, 이전에 복호화된 영역이다.

 

40101F 주소에서 messagebox() 함수를 호출하는데 인자값 부분의 값들이 어떤 문자열들인지 안 보이는 것으로 보아 아직 복호화가 덜 됐다는 걸 알 수 있다.

 

401000 주소 ~ 40100E 주소까지가 403000 주소부터 403128 주소까지의 영역을 대상으로 xor 연산하여 복호화 하는 하는 루프인데

MessageBox() 함수의 인자로 들어가는 40307D 주소와 403034 주소는 위의 복호화 대상 영역에 포함되는 주소이다.

 

암호화 된 403000 ~ 403128 영역
복호화 된 403000 ~ 403128 영역

 

401000 주소 ~ 40100E 주소에서 복호화 작업을 수행하고 나면 위와 같이 문자열들이 보이게 되는데

 

2byte를 패치해서 Nag를 없애라는 문구와 nag 창에서 봤던 문구가 보인다.

 

 

그리고 나서 F8 키를 눌러 40101F 주소에서 MessageBoxA() 함수를 호출하면 위와 같이 메세지 창이 뜬다.

 

 

메세지 창을 종료하면 위와 같이 401024 주소에서 40106A 주소로 점프하는데 위의 사진 부분에서 2가지 패치 방법이 있다.

 


패치 1

 

 

MessageBoxA() 함수를 호출 후 40106A 주소로 점프하기 때문에

 

MessageBoxA() 함수에 첫 번째로 들어가고 있는 401011 주소의 push 0 명령어를 위와 같이 jmp 0x40106A로 바꿔줌으로써 40101F 주소에서 Nag 창을 띄우는 MessageBoxA() 함수를 호출하는 명령어를 건너뛰고 바로 40106A 주소로 점프하도록 한다.

 

패치 2

 

 

https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-messagebox

 

MessageBoxA() 함수의 첫 번째 인자는 프로그램의 핸들 값이다.

 

 

위의 링크를 참고하면 첫 번째 인자가 NULL이면 메시지 박스가 나타나지 않는다고 되어 있는데 그렇다면 첫 번째 인자로 push 0 이라고 되어 있는 부분을 NULL 문자를 의미하는 0A를 넣어 Nag 창이 생성되지 않도록 한다.

 


 

 

MessageBoxA() 함수 호출이 끝난 후 40106A 주소로 점프하면 위와 같다.

 

edi에 값을 더하고 더한 값에 해당하는 주소에 mov 명령어로 값을 저장한다.

 

그리고 4010B4 주소에서 edi 레지스터에 담긴 값에 해당하는 주소의 함수를 호출하는데 edi에는 401011 주소가 담겨있다.

 

F7 키를 눌러 401011 주소로 이동한다.

 

 

그럼 위와 같이 스택에 값을 넣고 401021 주소에서 4010B6 주소에 있는 함수를 호출하는데

 

 

4010B6 주소에 있는 함수를 호출하면 위와 같이 main 창이 뜬다.

 

 

main 창을 닫으면 401026 주소에서 401054 주소로 점프한다.

 

401054 주소에서는 401320 주소의 함수를 호출한다.

 

 

401320 주소의 함수는 위와 같은데

 

403000 주소 ~ 403128 주소 영역의 데이터를 8D와 xor 연산하여 암호화한다.

 

그리고 401325 주소로 점프한다.

 

참고)

다형성 코드

- 원본 코드를 손상 시키지 않으면서 변조 시키는 코드이다.

바이러스나 쉘 코드 그리고 웜 등에서 자신의 존재를 숨기기 위해서 사용한다.

안티 바이러스나 IDS 대부분에서는 컴퓨터에 설치된 파일을 검색하거나 네트워크를 통해 전송되는 패킷을 검사하여 악성 코드를 찾아내 올바른 처리 방법을 수행하는 알고리즘을 사용한다.

그러므로 다형성 알고리즘은 코드를 변조 시키기 때문에 보안 솔루션에서 사용되는 알고리즘을 우회할 때 사용하기도 한다.

그리고 이번 바이너리 파일에서와 같이 암호화 하는 것은 다형성 코드에서 사용되는 방법 중 가장 흔하게 사용되는 방법이지만, 모든 코드들을 암호화 시키는 것이 아니라 약간 남겨두는 부분이 존재하는데, 그 이유는 암호화된 소프트웨어를 동작시키기 위해서 사용되는 부분이기 때문에 남겨두는 것이다.

그렇기에 안티 바이러스들은 약간 남겨두는 부분을 목표로 하여 악성 코드를 탐지하기 때문에, 악성 코드 제작자들은 이런 탐지 기법에서 자신들의 다형성 코드를 방어하기 위해 바이러스나 웜이 다른 곳으로 감염되거나 전파 될 때마다 복호화 코드를 작성시킨다.

 

변종 코드

- 자기 자신을 다시 프로그래밍 할 수 있는 코드를 말한다.

보통 자신의 코드를 임시적으로 다르게 변형시키고, 다시 원래 코드를 돌아오는 방식을 사용한다.

바이러스들이 다른 파일을 감염시키지만, children 코드가 parent 코드처럼 보이지 않게 하기 위해 사용한다.
(감염을 시키는 파일을 parent, 감염된 파일을 children 이라고 한다.)

안티 바이러스의 패턴 매칭 탐지 기법을 우회하기 위해 사용하는데, 실제 핵심 알고리즘은 변경되지 않지만 그 외의 자잘한 것들은 전부 변종된다고 봐도 무방하다.

변종 코드는 다형성 코드 보다 탐지 회피에 있어서 더 효과적인데, 안티 바이러스들이 패턴 매칭 방식으로 알려진 바이러스 코드를 찾기 때문이다.

또한 한 바이러스가 n개 이상의 OS를 감염시킬 때 사용하기도 한다.

보통 OS에 따라서 감염 코드를 작성하고 이런 코드를 하나로 합쳐서 슈퍼 바이러스를 만들어 감염시킨다.

 

401320 주소의 함수에서 암호화 루프를 거치기 전

 

401320 주소의 함수에서 암호화 루프를 거치고 난 후

 

401320 주소의 함수에서 암호화 루프를 거치기 전에는 403000 주소 ~ 403128 주소에서 읽을 수 있는 문자열들이 보이지만

 

401320 주소의 함수에서 암호화 루프를 거치고 난 후에는 위와 같이 알아볼 수 없게 변형된다.

 

 

401320 주소의 함수가 끝나면 401059 주소로 return 되는데 401059 주소에서는 4012C2 주소의 함수를 호출한다.

 

 

4012C2 주소의 함수는 위와 같은데 ExitProcess 함수를 호출하는 것 밖에 없다.

 

즉, 4012C2 주소의 함수에서 프로그램이 완전히 종료된다.

 


최종 패치

 

 

이전에 위에서 2가지 패치 방법을 통해 패치를 했지만 파일을 다시 시작하면 암호화 되기 때문에 패치 내용은 사라지게 된다.

 

패치 1번 방법에서는 MessageBoxA() 함수의 마지막 인자 부분의 값을 push 0에서 jmp 40106A 명령어로 수정함으로써 메세지 창을 띄우지 않고 건너뛰게 하고

 

패치 2번 방법에서는 MessageBoxA() 함수의 첫 번째 인자 부분의 값을 push 0에서 push 0A로 함으로써 NULL 값을 주어 메세지 창이 뜨지 않게 했지만

 

Ctrl + F2 키를 눌러 프로그램을 재실행하여 MessageBoxA() 함수 부분이 있던 401010 주소로 가보면 위와 같이 암호화 되어 있다.

 

 

프로그램 시작 후 401299 주소에서 40130F 함수를 호출하는데

 

40130F 주소의 함수 내에서 401314 주소의 5A와 xor 연산 이후 401000 ~ 401314 영역의 데이터가 복호화 되고

 

 

복호화 된 영역 중 401013 주소에서 6A를 edi(401011)로부터 2byte 영역에 저장함으로써  401011 주소에 push 0 명령어가 생성된다.

 

즉, 401016, 401617 주소에 있는 6A 00 값에 의해 push 0 명령어가 생성되는 것이다.

 

패치를 위해서는 push 0 명령어가 생성되는 것이 아니라 jmp 40106A 명령어가 생성되어야 하는데 jmp 40106A 명령어는 op code로 EB 57이다.

 

그렇다면 xor 연산 이후 결과가 push 0을 의미하는 6A 00이 아니라 EB 57이 되어야 한다는 것이다.

 

 

xor 연산의 특성을 이용하면

 

0x5A ^ 0xEB = B1 (복호화 되기 전 암호화 되어 있는 코드에 있어야 하는 값)

0x5A ^ 0x57 = 0D (복호화 되기 전 암호화 되어 있는 코드에 있어야 하는 값) 

 

위와 같이 값이 나올 것이다.

 

 

Ctrl + F2 키를 눌러 프로그램을 재실행 

EP 코드로 이동한 뒤

Ctrl + G 키를 눌러 401016을 입력하여 401016 주소로 이동하면 위와 같이 있는데

 

 

401016 주소를 선택한 다음 Ctrl + 9 키를 눌러 위와 같이 NOP으로 채우고

 

 

401016 주소와 401017 주소를 드래그하여 선택한 뒤 Ctrl + E 키를 눌러 위와 같이 b1 0d 입력 후 확인 버튼을 누른다.

 

 

그리고 Ctrl + P 키를 눌러 파일 패치를 하는데

 

위와 같이 모두 선택 해제 해준 뒤  Ctrl 키를 누른 상태에서 401016, 401017 주소만 선택하고 파일 패치 버튼을 눌러 파일로 저장한다.

 

 

패치 후 저장한 파일을 실행하면 위와 같이 Nag 창은 안 뜨고 main 창만 뜨게 된다.

 

 

반응형

+ Recent posts