PEB Struct
nt!_PEB +0x000 InheritedAddressSpace : UChar +0x001 ReadImageFileExecOptions : UChar +0x002 BeingDebugged : UChar +0x003 SpareBool : UChar +0x004 Mutant : Ptr32 Void +0x008 ImageBaseAddress : Ptr32 Void +0x00c Ldr : Ptr32 _PEB_LDR_DATA +0x010 ProcessParameters : Ptr32 _RTL_USER_PROCESS_PARAMETERS +0x014 SubSystemData : Ptr32 Void +0x018 ProcessHeap : Ptr32 Void +0x01c FastPebLock : Ptr32 _RTL_CR..
2015.09.15
no image
Packer
http://corkami.googlecode.com/files/packers.pdf Packers are most commonly used for compression, code obfuscation, and malware anti-reversing. While not always malicious, packers are often a clue to look a little deeper into a particular binary. Ange Albertini did a marvelous job of representing the (known) universe of executable packers in this infographic.
2015.09.05
Contents of the TIB (32-bit Windows)
Contents of the TIB (32-bit Windows)[edit]PositionLengthWindows VersionsDescriptionFS:[0x00]4Win9x and NTCurrent Structured Exception Handling (SEH) frameFS:[0x04]4Win9x and NTStack Base / Bottom of stack (high address)FS:[0x08]4Win9x and NTStack Limit / Ceiling of stack (low address)FS:[0x0C]4NTSubSystemTibFS:[0x10]4NTFiber dataFS:[0x14]4Win9x and NTArbitrary data slotFS:[0x18]4Win9x and NTLine..
2015.09.04
no image
Anti Virtual Machine
들어가기 전에멀웨어 코더들은 분석을 방해할 목적으로 안티 가상머신 기법을 사용한다. 이 기법을 이용해 악성코드가 가상머신 내에 실행 여부를 탐지할 수 있으며, 가상 머신을 탐지하면 악성코드는 원래와 다르게 실행하거나 전혀 실행하지 않는다. 여기서는 일반적으로 VMware를 대상으로 하는 안티 가상머신기법에 대하여 알아볼 것이다. VMware ArtifactsVMware환경은 시스템에 많은 흔적을 남기며, 특히 VMware Tools를 설치했을 경우 그렇다.악성코드는 파일 시스템이나 레지스트리, 프로세스 목록에 존재하는 흔적을 VMware를 탐지하는데 사용한다. 아래의 그림은 VMware를 설치해놓고 사용을 했던 나의 PC의 프로세스 목록이다. 확실히 많은 프로세스가 실행 중임을 알 수 있고, 이들 중 하..
2015.09.03
no image
Anti Debugging
Windows Debugger Detection악성코드는 자신이 디버거에 의해 동작되고 있다는 것을 알아내기 위한 방법으로 윈도우 API를 사용하는 방법과 디버깅하는 동안에 발견되는 특징을 찾기 위해 메모리 구조를 수동으로 검사하거나 디버거가 남기는 잔여물을 찾기 위해 시스템을 검색하는 등 다양한 기법을 사용한다. 디버거 탐지는 악성코드가 수행하는 안티디버깅 방법중 가장 일반적이다. Using the Windows API윈도우 API 함수 사용은 가장 명백한 안티 디버깅 기법이다. 윈도우 API는 프로그램 자신이 디버깅 중인지 확인할 수 있는 몇개의 함수를 제공한다. 이러한 함수 중 일부는 디버거 탐지를 위한 목적이지만, 다른 함수는 이와 다른 목적임에도 디버거를 탐지하는데 사용할 수 있다.전형적으로 안..
2015.09.03
no image
Anti disassembly
Understanding Anti Disassembly안티 디스어셈블리 구현 시 악성코드 제작자는 디스어셈블러를 속여 실제 실행과 다른 명령어들의 목록을 디스어셈블러에 보이게 일련의 과정을 생성한다. 안티 디스어셈블리 기법은 디스어셈블러의 가정과 제약 사항을 이용한다. 예를 들어 디스어셈블러는 한번에 명령어 하나로 프로그램의 각 바이트를 표현하지만 이러한 잘못된 오프셋에서 디스어셈블하게 교묘히 조작하면 유효한 명령을 화면에서 숨길 수 있다. 아래의 코드를 살펴보자. 이 코드는 IDA Pro로 확인했을 경우에 보이는 코드이다. 40100E의 위치에 있는 JZ 401011 명령어가 존재하고 있다. 하지만 디스어셈블러는 401010의 명령어를 보여주며 심지어 잘못된 주소를 호출하고자 하는 것을 확인할 수가 있..
2015.09.01
DLL Injection
2015.08.29
no image
데이터 인코딩
악성코드 분석 과정에서 데이터 인코딩이란 의도를 숨길 목적으로 내용을 수정하는 모든 형태를 말한다. 즉, 악성코드는 악의적인 행위를 숨기기 위해 인코딩 기법을 사용하므로, 악성코드 분석가로서 악성코드를 완전히 이해하기 위해 이런 기법들을 이해해야 한다. 인코딩 알고리즘 분석의 목적악성코드는 인코딩을 다양한 목적으로 사용하는데 일반적으로 네트워크 기반 통신의 암호화를 위해 사용한다. 악성코드는 내부 작업을 숨기기 위해서도 인코딩을 사용한다. 예를 들어 다음과 같은 목적으로 인코딩을 할 수 있다.- C&C 도메인 같은 설정을 숨기기 위하여- 정보를 훔치기 전에 임시 파일에 저장하기 위하여- 악성코드에서 사용하는 문자열을 저장하고 사용하기 전에 디코딩하기 위해- 악의적인 활동에 쓰이는 문자열을 숨김으로써 악성..
2015.08.26

PEB Struct

Kail-KM
|2015. 9. 15. 02:01

nt!_PEB
+0x000 InheritedAddressSpace : UChar
+0x001 ReadImageFileExecOptions : UChar
+0x002 BeingDebugged : UChar
+0x003 SpareBool : UChar
+0x004 Mutant : Ptr32 Void
+0x008 ImageBaseAddress : Ptr32 Void
+0x00c Ldr : Ptr32 _PEB_LDR_DATA
+0x010 ProcessParameters : Ptr32 _RTL_USER_PROCESS_PARAMETERS
+0x014 SubSystemData : Ptr32 Void
+0x018 ProcessHeap : Ptr32 Void
+0x01c FastPebLock : Ptr32 _RTL_CRITICAL_SECTION
+0x020 FastPebLockRoutine : Ptr32 Void
+0x024 FastPebUnlockRoutine : Ptr32 Void
+0x028 EnvironmentUpdateCount : Uint4B
+0x02c KernelCallbackTable : Ptr32 Void
+0x030 SystemReserved : [1] Uint4B
+0x034 AtlThunkSListPtr32 : Uint4B
+0x038 FreeList : Ptr32 _PEB_FREE_BLOCK
+0x03c TlsExpansionCounter : Uint4B
+0x040 TlsBitmap : Ptr32 Void
+0x044 TlsBitmapBits : [2] Uint4B
+0x04c ReadOnlySharedMemoryBase : Ptr32 Void
+0x050 ReadOnlySharedMemoryHeap : Ptr32 Void
+0x054 ReadOnlyStaticServerData : Ptr32 Ptr32 Void
+0x058 AnsiCodePageData : Ptr32 Void
+0x05c OemCodePageData : Ptr32 Void
+0x060 UnicodeCaseTableData : Ptr32 Void
+0x064 NumberOfProcessors : Uint4B
+0x068 NtGlobalFlag : Uint4B
+0x070 CriticalSectionTimeout : _LARGE_INTEGER
+0x078 HeapSegmentReserve : Uint4B
+0x07c HeapSegmentCommit : Uint4B
+0x080 HeapDeCommitTotalFreeThreshold : Uint4B
+0x084 HeapDeCommitFreeBlockThreshold : Uint4B
+0x088 NumberOfHeaps : Uint4B
+0x08c MaximumNumberOfHeaps : Uint4B
+0x090 ProcessHeaps : Ptr32 Ptr32 Void
+0x094 GdiSharedHandleTable : Ptr32 Void
+0x098 ProcessStarterHelper : Ptr32 Void
+0x09c GdiDCAttributeList : Uint4B
+0x0a0 LoaderLock : Ptr32 Void
+0x0a4 OSMajorVersion : Uint4B
+0x0a8 OSMinorVersion : Uint4B
+0x0ac OSBuildNumber : Uint2B
+0x0ae OSCSDVersion : Uint2B
+0x0b0 OSPlatformId : Uint4B
+0x0b4 ImageSubsystem : Uint4B
+0x0b8 ImageSubsystemMajorVersion : Uint4B
+0x0bc ImageSubsystemMinorVersion : Uint4B
+0x0c0 ImageProcessAffinityMask : Uint4B
+0x0c4 GdiHandleBuffer : [34] Uint4B
+0x14c PostProcessInitRoutine : Ptr32 void 
+0x150 TlsExpansionBitmap : Ptr32 Void
+0x154 TlsExpansionBitmapBits : [32] Uint4B
+0x1d4 SessionId : Uint4B
+0x1d8 AppCompatFlags : _ULARGE_INTEGER
+0x1e0 AppCompatFlagsUser : _ULARGE_INTEGER
+0x1e8 pShimData : Ptr32 Void
+0x1ec AppCompatInfo : Ptr32 Void
+0x1f0 CSDVersion : _UNICODE_STRING
+0x1f8 ActivationContextData : Ptr32 Void
+0x1fc ProcessAssemblyStorageMap : Ptr32 Void
+0x200 SystemDefaultActivationContextData : Ptr32 Void
+0x204 SystemAssemblyStorageMap : Ptr32 Void
+0x208 MinimumStackCommit : Uint4B

'Reversing > Theory' 카테고리의 다른 글

악성코드 분석 방법  (0) 2016.02.26
악성코드 선호 경로  (0) 2015.09.27
Packer  (0) 2015.09.05
Contents of the TIB (32-bit Windows)  (0) 2015.09.04
Anti Virtual Machine  (0) 2015.09.03

Packer

Kail-KM
|2015. 9. 5. 14:30


packers.pdf

http://corkami.googlecode.com/files/packers.pdf


Packers are most commonly used for compression, code obfuscation, and malware anti-reversing. While not always malicious, packers are often a clue to look a little deeper into a particular binary. Ange Albertini did a marvelous job of representing the (known) universe of executable packers in this infographic.




'Reversing > Theory' 카테고리의 다른 글

악성코드 선호 경로  (0) 2015.09.27
PEB Struct  (0) 2015.09.15
Contents of the TIB (32-bit Windows)  (0) 2015.09.04
Anti Virtual Machine  (0) 2015.09.03
Anti Debugging  (0) 2015.09.03

Contents of the TIB (32-bit Windows)[edit]

PositionLengthWindows VersionsDescription
FS:[0x00]4Win9x and NTCurrent Structured Exception Handling (SEH) frame
FS:[0x04]4Win9x and NTStack Base / Bottom of stack (high address)
FS:[0x08]4Win9x and NTStack Limit / Ceiling of stack (low address)
FS:[0x0C]4NTSubSystemTib
FS:[0x10]4NTFiber data
FS:[0x14]4Win9x and NTArbitrary data slot
FS:[0x18]4Win9x and NTLinear address of TIB
---- End of NT subsystem independent part ----
FS:[0x1C]4NTEnvironment Pointer
FS:[0x20]4NTProcess ID (in some windows distributions this field is used as 'DebugContext')
FS:[0x24]4NTCurrent thread ID
FS:[0x28]4NTActive RPC Handle
FS:[0x2C]4Win9x and NTLinear address of the thread-local storage array
FS:[0x30]4NTLinear address of Process Environment Block (PEB)
FS:[0x34]4NTLast error number
FS:[0x38]4NTCount of owned critical sections
FS:[0x3C]4NTAddress of CSR Client Thread
FS:[0x40]4NTWin32 Thread Information
FS:[0x44]124NT, WineWin32 client information (NT), user32 private data (Wine), 0x60 = LastError (Win95), 0x74 = LastError (WinME)
FS:[0xC0]4NTReserved for Wow64. Contains a pointer to FastSysCall in Wow64.
FS:[0xC4]4NTCurrent Locale
FS:[0xC8]4NTFP Software Status Register
FS:[0xCC]216NT, WineReserved for OS (NT), kernel32 private data (Wine)

herein: FS:[0x124] 4 NT Pointer to KTHREAD (ETHREAD) structure

FS:[0x1A4]4NTException code
FS:[0x1A8]18NTActivation context stack
FS:[0x1BC]24NT, WineSpare bytes (NT), ntdll private data (Wine)
FS:[0x1D4]40NT, WineReserved for OS (NT), ntdll private data (Wine)
FS:[0x1FC]1248NT, WineGDI TEB Batch (OS), vm86 private data (Wine)
FS:[0x6DC]4NTGDI Region
FS:[0x6E0]4NTGDI Pen
FS:[0x6E4]4NTGDI Brush
FS:[0x6E8]4NTReal Process ID
FS:[0x6EC]4NTReal Thread ID
FS:[0x6F0]4NTGDI cached process handle
FS:[0x6F4]4NTGDI client process ID (PID)
FS:[0x6F8]4NTGDI client thread ID (TID)
FS:[0x6FC]4NTGDI thread locale information
FS:[0x700]20NTReserved for user application
FS:[0x714]1248NTReserved for GL
FS:[0xBF4]4NTLast Status Value
FS:[0xBF8]532NTStatic UNICODE_STRING buffer
FS:[0xE0C]4NTPointer to deallocation stack
FS:[0xE10]256NTTLS slots, 4 byte per slot
FS:[0xF10]8NTTLS links (LIST_ENTRY structure)
FS:[0xF18]4NTVDM
FS:[0xF1C]4NTReserved for RPC
FS:[0xF28]4NTThread error mode (RtlSetThreadErrorMode)



참고


https://en.wikipedia.org/wiki/Win32_Thread_Information_Block#Accessing_the_TIB        ; FS 레지스터를 참고한 사이트

https://en.wikipedia.org/wiki/Process_Environment_Block                                ; FS:[0x30]에 있는 PEB에 관한 더 자세한 자료


'Reversing > Theory' 카테고리의 다른 글

PEB Struct  (0) 2015.09.15
Packer  (0) 2015.09.05
Anti Virtual Machine  (0) 2015.09.03
Anti Debugging  (0) 2015.09.03
Anti disassembly  (0) 2015.09.01

들어가기 전에


멀웨어 코더들은 분석을 방해할 목적으로 안티 가상머신 기법을 사용한다. 이 기법을 이용해 악성코드가 가상머신 내에 실행 여부를 탐지할 수 있으며, 가상 머신을 탐지하면 악성코드는 원래와 다르게 실행하거나 전혀 실행하지 않는다. 여기서는 일반적으로 VMware를 대상으로 하는 안티 가상머신기법에 대하여 알아볼 것이다.



VMware Artifacts


VMware환경은 시스템에 많은 흔적을 남기며, 특히 VMware Tools를 설치했을 경우 그렇다.악성코드는 파일 시스템이나 레지스트리, 프로세스 목록에 존재하는 흔적을 VMware를 탐지하는데 사용한다.

아래의 그림은 VMware를 설치해놓고 사용을 했던 나의 PC의 프로세스 목록이다. 확실히 많은 프로세스가 실행 중임을 알 수 있고, 이들 중 하나를 선택하여 악성코드는 프로세스 목록에서 VMwae와 관련된 문자열을 검색하는 방식으로 탐지가 가능하다.



프로세스 목록 뿐만 아니라 시스템에 설치한 서비스를 찾기 위해 레지스트리를 검색하거나 다음 명령어를 사용하여 서비스 목록에 위치한 VMware와 관련된 항목들을 나열할 수가 있고 이를 통하여 악성코드는 가상 머신의 여부를 확인할 수가 있다.

또한 가상머신은 다양한 방법으로 네트워크에 연결할 수 있는데, 이 모든 방시은 가상머신이 고유의 가상 네트워크 인터페이스 카드(NIC)를 가진다. VMware가 NIC를 가상화하려면 가상머신의 MAC 주소를 만들어야하며, 설정에 따라 네트워크 어댑터를 이용해 VMware 사용 여부도 확인할 수 있다.

MAC 주소의 처음 3 바이트는 일반적으로 업체를 명시하는데, VMware는 00:0C:29로 시작하는 MAC 주소를 할당한다(*하지만 내 PC에서 확인해본 결과 00-50-56으로 시작하였다. 일반적으로 버전마다 변한다.).



Bypassing VMware Artifact Searching

Vmware 흔적을 검색하는 악성코드 무력화는 일반적으로 간단히 검사확인과 패치 두 단계를 거친다. 예를 들어 아래의 그림을 보자. 악성코드가 프로세스 목록을 가져 온 뒤 Vmware와 관련이 있는 문자열 "VMwareTray.exe"를 가져온 후 strncmp 함수를 호출하여 악성코드가 가상 머신의 여부를 판단할 수가 있다.

이 탐지를 피하기 위해서는 4010A5에 있는 점프를 실행하지 않게 디버깅 도중에 바이너리를 패치하거나 해당 문자열을 수정하여 걸리지 않도록하는 등 회피 방법이 존재하고 있다.


Checking for Memory Artifacts

VMware는 가상화 프로세스의 결과로 메모리에 많은 흔적을 남긴다. 일부는 중요한 프로세서 구조인데, 가상머신에서 이를 이동하거나 변경해서 인지할 수 있는 흔적을 남기기 때문이다. 일반적으로 메모리 흔적을 탐지할 때 사용되는 기술은 물리적 메모리에서 문자열 VMware을 탐지하는 방식으로 발견한 흔적에서 수백개의 문자열을 탐지해 낼 수 있다.



Vulnerable Instructions


가상머신 모니터 프로그램은 가상머신의 실행을 모니터링한다. 이는 가상 플랫폼과 함께 게스트 운영체제를 나타낼 수 있게 호스트 운영체제 이ㅜ에서 동작한다. 이 역시 악성코드가 가상화를 탐지할 수 있는 일부 보안 취약점을 갖고 있다.

일부 x86 명령어는 하드웨어 기반 정보에 접근하지만 인터럽트를 생성하지 않는다. 그런 명령어에는 sidt, sgdt, sldt, cupid 등이 있다. 이 명령어를 적절히 가상화시키려면 VMware는 모든 명령어에서 바이너리 해석하는 과정이 필요한데, 이는 결과적으로 엄청난 성능 저하를 가져온다. 이러한 성능 저하를 막기 위해 VMware는 특정 명령어의 경우 제대로 가상화하지 않고 실행한다.


Using the Red Pill Anti-VM Technique

레드 필은 sidt 명령어를 실행해서 IDTR 레지스터 값을 얻는 안티 VM 기법이다. 가상 모니터는 게스트의 IDTR을 재배치해서 호스트의 IDTR과 충돌을 피해야한다. 가상머신 모니터는 가상머신이 sidt 명령어를 실행하는 시점을 알지 못하므로 가상머신의 IDTR을 반환한다. 레드 필은 이 불일치함을 테스트해서 VMware의 사용 여부를 탐지한다.

악성코드는 sidt 명령어를 이용해 EAX가 가리키는 메모리 위치로 IDTR 내용을 저장한다. IDTR은 6바이트이고 다섯번째 바이트 오프셋이 베이스 메모리 주소 시작점을 갖고 있다. 다섯 번째 바이트를 VVMware 시그니처인 0xFF와 비교한다.

이러한 레드 필은 단일 프로세서를 사용하는 장비에서만 성공한다. 그러므로 멀티프로세서 장비에서 실행하거나 sidt 명령어를 삭제하면 우회가 가능하다.


Using the No Pill Technique

VMware 탐지에 사용하는 sgdt와 sldt 명령어 기법은 주로 No Pill로 알려져있다. 레드필과는 다르게 LDT 구조체를 운영체제가 아닌 프로세서에 할당한다는 사실에 의존한다. 호스트 머신에서 LDT 위치는 0이고, 가상머신에서는 0이 아니다. sldt 방식은 가속 기능을 비활성화해서 VMware에서 사용하지 못하게 할 수 있다. 이를 위해 VM > Settings > Processors를 선택하고 Disable Acceleration 체크박스에 체크한다.


Querying the I/O Communication Port

현재 사용하는 가장 대중적인 안티VMware 기법은 I/O 통신 포트를 질의하는 방식일 것이다. Vmware는 가상 I/O 포트를 이용해 가상머신과 호스트 운영체제 사이에서 두 시스템 간의 복사와 붙여넣기 같은 기능을 지원한다. 포트를 질의하고 VMware 사용을 식별하는 매직넘버와 비교할 수 있다.

VMware는 명령어 사용을 모니터링하고 통신 채널 포트 0x5668(VX)로 목적지 I/O를 캡처한다. 따라서 두번째 오퍼랜드는 VMware를 확인할 목적으로 VX를 로드할 필요가 있으며, EAX 레지스터는 매직 넘버인 0x564D5868(VMXh)을 로드한다.

우선 악성코드는 매직 넘버인 0x564D5868을 1의 EAX 레지스터로 로드한다. 그 후 ECX는 0xA 값을 로드해서 VMware 버전 유형을 알아낸다. 2에서는 해당 값을 통해 VMware I/O 통신 포트를 지정하는 in 명령어에 사용한다. 실행시 in 명령어는 가상머신이 트랩해서 실행을 에뮬레이션한다. 3에서 코드가 가상 머신 동작 여부를 확인한다.

이 기법을 우회하는 가장 간단한 방법은 in 명령어를 NOP 처리하거나 조건부 점프를 패치해서 비교 결과와 상관없이 점프하는 방식이다.


Using the str Instruction

str 명령어는 실행중인 TSS(Task State Segment)를 가리킨다. 악성코드 제작자는 str 명령어가 가상머신과 실제 시스템이 다른 값을 반환한다는 사실을 이용해 이 명령어로 가상머신 존재여부를 탐지한다.


Anti-VM x86 Instructions

지금까지 안티 VM 기법에 이용하는 악성코드의 가장 일반적인 명령어를 살펴봤다. 이 명령어에는 다음과 같은 것들이 있다.

-sidt    -sgdt    -sldt    -smsw    -str    -in    -cpuid

악성코드는 전형적으로 VMware 탐지를 수행하지 않는 경우 이 명령어를 실행하지 않으며, 탐지 우회는 역시 이 명령어 호출을 피하는 바이너리로 패치만 하면 되므로 간단하다. 이 명령어는 기본적으로 사용자 모드에서 실행할 경우 무의미하므로 이 명령어가 보이면 안티 VMware 코드의 일부일 가능성이 있음을 알 수 있다.


요약


- 프로세스 목록    - 서비스와 레지스트리    - MAC 주소

- sidt, sgdt, sldt, cpuid    - in 통신포트 VMxh, VX, 0x5668, 0x564D5868    - str 명령어



'Reversing > Theory' 카테고리의 다른 글

Packer  (0) 2015.09.05
Contents of the TIB (32-bit Windows)  (0) 2015.09.04
Anti Debugging  (0) 2015.09.03
Anti disassembly  (0) 2015.09.01
DLL Injection  (0) 2015.08.29

Anti Debugging

Kail-KM
|2015. 9. 3. 03:32

Windows Debugger Detection


악성코드는 자신이 디버거에 의해 동작되고 있다는 것을 알아내기 위한 방법으로 윈도우 API를 사용하는 방법과 디버깅하는 동안에 발견되는 특징을 찾기 위해 메모리 구조를 수동으로 검사하거나 디버거가 남기는 잔여물을 찾기 위해 시스템을 검색하는 등 다양한 기법을 사용한다. 디버거 탐지는 악성코드가 수행하는 안티디버깅 방법중 가장 일반적이다.


Using the Windows API

윈도우 API 함수 사용은 가장 명백한 안티 디버깅 기법이다. 윈도우 API는 프로그램 자신이 디버깅 중인지 확인할 수 있는 몇개의 함수를 제공한다. 이러한 함수 중 일부는 디버거 탐지를 위한 목적이지만, 다른 함수는 이와 다른 목적임에도 디버거를 탐지하는데 사용할 수 있다.

전형적으로 안티디버깅 API 함수 호출을 막기 위한 가장 쉬운방법은 실행중에 안티디버깅 API 함수들을 호출하지 않게 악성코드를 수동으로 조작하거나 올바른 경로를 취했는지 보장하기 위해 호출되는 플래그를 사전에 수정하는 방식이다. 다음과 같은 윈도우 API 함수들은 안티디버깅으로 사용할 수 있다.


· IsDebuggerPresent

디버거를 탐지하는 가장 간다한 API 함수는 IsDebuggerPresent다. 이 함수는 PEB 구조에서 IsDebugged 필드를 찾아 디버거 환경에서 동작 중이 아니라면 0을 반환하고, 디버거 환경에서 동작하고 있다면 0이 아닌 값을 반환한다.

*PEB는 FS 레지스터를 통해 접근이 가능하며 TEB의 0x30 이 PEB를 기리킨다. 따라서 FS:[0x30] 이라 되어있으면 PEB를 가리키고있다는 것이다.

· CheckRemoteDebuggerPresent

이 함수는 위의 함수와 거의 동일하며 이 함수 또한 PEB 구조에 있는 IsDebugged 필드를 확인하지만, 자기 자신이나 로컬 컴퓨터의 다른 프로세스에 대해서만 검사할 수 있다. 이 함수는 파라미터로 프로세스 핸들을 받아 프로세스가 디버거 환경에서 구동 여부를 확인한다. 단순히 CheckRemoteDebuggerPresent는 프로세스에 핸들을 저날해 프로세스를 확인하는데 사용한다.

· tQueryInformationProcess

이 함수는 주어진 프로세스에 관한 정보를 검색할 수 있는 Ntdll.dll 내의 네이티브 API 함수이다. 첫번째 파라미터는 프로세스 핸들이고, 두번째는 검색하고자 하는 프로세스 정보의 타입을 함수에 알려주는데 사용한다. 두번째 파라미터가 ProcessDebugPort(0x7)의 값이라면 첫번째 파라미터에 해당하는 프로세스가 지금 디버깅 중인지를 알려준다. 프로세스가 디버깅 중이 아니라면 0을 반환할 것이고, 그렇지 않다면 디버거 포트 번호를 반환할 것이다.

· OutputDebugString

이 함수는 디버거에 출력할 문자열을 전달하는데 사용되는데 이를 디버거의 존재를 탐지하기 위해 사용할 수 있다. 아래의 코드를 보면 SetLastError를 이용해 현재 에러코드를 임의의 값을 설정한다. OutputDebugString을 호출할때 디버거에 붙어있지 않아 실패할 경우 이 함수는 에러코드를 설정하므로 GetLastError 함수는 더 이상 임의의 값을 갖지 않는다. 하지만 디버거환경에서 OutputDebugString 함수를 호출하면 OuputDebugString 함수는 성공하고 GetLastError 함수 값은 변하지 않는다.


Manually Checking Structures

윈도우 API 사용이 디버거의 존재를 탐지하는 가장 명확한 방법이지만, 악성코드 제작자는 가장 일반적으로 구조체를 수동으로 검사하는 방식을 사용한다. 수동 검사를 수행함에 있어 PEB 구조체 안에 있는 일부 플래그에서 디버거의 존재에 관한 정보를 제공한다. 이에 대하여 알아보자.

· BeingDebugged 플래그 검사

아래의 그림과 같이 운영체제는 실행 중인 각 프로세스에 대해 윈도우 PEB 구조체를 관리한다. 프로세스와 관련한 모든 사용자 모드 파라미터를 갖고 있다. 이 파라미터는 환경 변수 값, 로드된 모듈 목록, 메모리 주소, 그리고 디버거 상태같은 프로세스의 환경 데이터를 포함한다.

프로세스 실행 중에 PEB 위치는 FS:[0x30]에서 참조할 수 있다. 악성코드는 안티디버깅을 수행하기 위해 특정 프로세스의 디버깅 여부를 알려주는 BeingDebugged 플래그 값을 확인하는 위치를 사용한다. 아래의 그림은 해당 검사를 수행하는 두가지 예이다.

좌측의 코드는 PEB 위치를 EAX 로 이동시키고 이 오프셋에 2를 더하여 EBX로 이동시키는데 바로 이 위치가 BeingDebugged 플래그 위치의 PEB 오프셋에 해당한다. 그 후 EBX가 0인지를 확인하는 것으로 EBX가 0이면, 즉 디버거가 동작하고 있지 않다면 디버거가 발견되지 않았음을 알고 NoDebuggerDetected로 이동한다. 우측의 코드는 push와 pop 명령어를 조합해 PEB 위치를 EDX로 이동한 후 EDX에서 오프셋 2에 있는 BeingDebugged 플래그를 1과 직접 비교한다. 

이 확인 과정은 다양한 형태를 취할 수 있지만, 궁극적으로 조건부 점프가 코드 경로를 결정한다. 이 문제를 해결하려면 다음과 같은 처리 방법 중 하나를 선택할 수 있다.

- 점프 명령어가 실행하기 직전에 ZF를 직접 수정해 점프를 취하거나 취하지 않게 강제한다.

- BeingDebugged 플래그를 직접 0으로 변경한다.


· ProcessHeap 플래그 검사

로더는 ProcessHeap으로 알려진 Reverse4 배열 내에 문서화하지 않은 위치를 할당된 프로세스의 첫번째 힙의 위치로 설정한다. ProcessHeap은 PEB 구조체의 0x18에 위치한다. 첫번째 힙은 디버거 내에서 힙의 생성 여부를 커널에게 알려주는 필드가 있는 헤더를 포함한다.

* 윈도우 버전에 따라 다른 오프셋에 위치할 수 있으며 값 또한 다르게 설정되어 있다.

이 기법을 극복하는 가장 좋은 방법은 ProcessHeap 플래그를 수동으로 변경하거나 사용하는 디버거의 플러그인을 사용하는 것이다.


· NTGlobalFlag 검사

프로세스를 디버거에서 시작할 때 약간 다르게 동작하므로 메모리 힙을 다르게 메모리 힙을 다르게 생성한다. 힙 구조체 생성을 결정할 때 사용하는 시스템 정보는 PEB의 0x68 오프셋에 있는 문서화하지 않은 위치에 저장된다. 이 위치의 값이 0x70 이라면 프로세스가 디버거에서 동작중이라는 사실을 알 수 있다.

0x70의 값은 디버거가 힙을 생성할 때 다음과 같은 플래그를 조합한다. 프로세스를 디버거 내에서 실행하면 프로세스는 이 플래그를 설정한다. 아래의 그림은 이 값을 확인하는 어셈블리 코드이다.

이 기법을 우회하는 가장 쉬운 방법은 수동으로 해당 플래그를 변경하거나 사용중인 디버거의 플러그인을 사용하는 방식이다.


Checking for System Residue

악성코드를 분석할 때 디버깅 도구를 사용하는데, 일반적으로 시스템에 흔적을 남긴다. 악성코드는 자신이 분석 중인지 여부를 확인하기 위해 디버거를 참조하는 레지스트리를 검색하는 방식으로 그 흔적을 찾을 수 있다. 아래 레지스트리 경로는 디버거가 사용하는 일반적인 위치다.

이 레지스트리 키는 애플리케이션에 에러가 발생할 때 활성화할 디버거를 지정한다. 기본적으로 Dr.Watson을 설정하지만 OllyDbg같은 디버거로 변경했다면 악성코드는 분석 중이라고 판단한다. 아래는 내 PC의 지정되어 있는 디버거가 vsjitdebugger.exe로 지정되어있는 것을 확인할 수가 있다.

악성코드를 분석하는 동안 악성코드는 일반적인 디버거 프로그램 실행 파일과 같은 시스템 파일과 폴더를 검색할 수도 있다. 또는 악성코드는 동작 중인 메모리에서 현재 프로세스 목록을 보거나 더 일반적으로 아래와 같이 FindWindow 함수를 통해 디버거 검색을 수행하는 등 흔적을 탐지한다.





Identifying Debugger Behavior


악성코드 분석가가 리버싱을 하기 위해 디버거는 BP를 설정하거나 프로세스를 단계별로 실행할 수 있다. 하지만 디버거에서 이런 작업을 수행할 때 프로세스 내의 코드를 수정한다. 일부 안티 디버깅 기법은 악성코드가 INT 스캐닝, 체크섬 검사, 시간 검사 같은 형태의 디버거 동작을 탐지하는데 사용한다.


INT Scanning

INT 3은 디버거가 사용하는 소프트웨어 인터럽트로 동작하는 프로그램 명령어를 INT 3로 임시 변경해 디버거 예외 핸들러를 호출하는데, 이는 BP를 설정하는 기본 메커니즘이다. INT 3의 OPCODE는 0xCC이다. 다시 말해 디버거를 이용해 브레이크 포인트를 설정할 때마다 디버거는 0xCC를 삽입함으로써 브레이크 포인트를 삽입해서 코드를 변경한다.

특정 INT 3 명령어뿐만 아니라 INT immediate는 3을 포함해 임의의 인터럽트를 설정할 수 있다. 1바이트인 INT 3과는 다르게 이는 0xCD 0xValue 와 같이 2바이트로 사용한다. 일반적인 안티 디버깅기법은 아래와 같이 0xCC 옵코드를 검색해서 자신의 코드를 INT 3으로 변경했는지 프로세스를 스캔하는 방식이다.

호출 명령어로 시작한 코드 다음 pop 명령어가 EIP를 EDI로 저장한다. 그러면 EDI는 다음 코드의 시작으로 조정된다. 그 코드는 0xCC 바이트를 검색한다. 0xCC 바이트를 발견하면 디버거가 존재한다는 사실을 알게된다. 이 기법은 소프트웨어 BP 대신 HardWare BP를 설정해 우회할 수 있다.


Performing Code Checksums

인터럽트 스캔과 동일한 목적으로 악성코드는 코드 섹션의 Checksum을 계산할 수 있다. 이는 0xCC를 검색하는 대신 간단히 순환 중복 검사(CRC)나 악성코드 OPCode MD5 체크섬을 계산한다. 이 기법 또한 하드웨어 BP를 설정해 우회하거나 디버거에서 실행 경로를 수동으로 변경해 우회할 수 있다. 아래의 사진은 ADD를 통하여 명령어들의 OPcode의 합을 계산하여 CMP를 통해 비교 후 분기 하는 것을 확인할 수가 있다.


Timing Checks

프로세스를 디버깅할 때는 그렇지 않을 때보다 훨씬 느려지기 때문에 timeing checks 방식은 악성코드가 디버거를 탐지할 때 사용하는 가장 대중적인 방법 중 하나다. 디버거 탐지에 사용하는 시간 검사에는 다음과 같은 몇가지 방식이 있다.

- 몇가지 동작 수행에 대해 타임스탬프를 기록한 후 다른 타임스탬프를 가져와 두개의 타임스탬프를 비교한다. 지연차가 있다면 디버거가 존재한다고 가정할 수 있다.

- 예외가 발생하기 전후의 타임스탬프를 가져온다. 프로세스가 디버그 중이 아니라면 신속하게 예외를 처리하지만, 디버거가 예외를 처리하는 경우 훨씬 느려질 것이다. 기본적으로 대다수 디버거는 예외 처리에 사람이 개입하게 해서 상당한 지연을 발생시킨다. 많은 디버거는 이를 위해 예외를 무시하거나 그냥 지나치게할 수 있는 기능을 제공하지만 이런 경우에도 꽤 긴 지연이 발생한다.


· rdtsc 명령어 사용

가장 일반적인 시간 검사 방법은 rdtsc 명령어(OPCode:0x0F31)를 사용한다. rdtsc 명령어는 가장 최근에 시스템이 리부팅한 이후 흐른 시간 값을 저장한 64 비트를 반환한다. 악성코드는 간단히 이 명령어를 두 번 실행하고 두 값을 비교한다.

위의 그림을 보면 rdtsc를 호출하여 값을 ecx에 저장하고 다시 한번 호출하여 두 값을 비교하는 것을 볼 수가 있다. 만약 그 값의 차가 크지 않을 경우 디버거에게 탐지되지 않았을 때의 명령어를 수행하게 되며 만약 값의 차가 특정한 정도를 넘으면 다시 한번 rdtsc를 호출하여 이 임의의 주소로 ret하게 되는 것을 확인할 수가 있다.

· QueryPerformanceCounter와 GetTickCount 사용

두개의 윈도우 API 함수는 rdtsc와 같이 시간차를 통해 안티디버깅을 수행한다. QueryPerformanceCounter는 비교에 사용할 시간차를 가져올 때 카운터 질의를 두번 호출 한다. 두 호출 사이의 시간차가 너무 크다면 디버거를 사용중이라고 할 수 있다. GetTickCount 함수는 마지막으로 시스템을 재부팅한 이후 경과 시간을 밀리초 단위의 숫자로 반환한다. 아래는 GetTickCounter의 사용 방식이다.

앞서 언급한 모든 시간차 공격은 디버깅 중이나 함수를 두번 연속 호출한 후 비교하는 형태를 식별해서 정적 분석하는 도중에 발견할 수가 있다. 이 방식은 시간차 확인에 사용한 두 호출 중간에 BP를 설정하거나 단계별로 실행했을 때만 디버거에서 찾아낼 수 있다. 그러므로 시간차 탐지를 회피할 수 있는 가장 쉬운 방법은 이런 확인을 그냥 실행한 후 BP를 설정하고 다시 단계별로 디버깅한다.





Interfering with Debugger Functionality


악성코드는 일반 디버거 동작을 방해하는 TLS Callback, 예외 처리, 인터럽트 삽입 같은 여러가지 기법을 사용할 수가 있다. 이 기법은 디버거 통제하에서 프로그램 실행 무력화를 시도하는 방식으로 진행이 된다.


Using TLS Callback

일반적으로 대다수 디버거는 PE 헤더에서 정의한 프로그램 진입점에서 시작한다. 그러나 TLS(Thread Local Storage) CallBack은 진입점에서 실행하기 전에 코드를 실행할 때 사용할 수 있으므로 디버거 몰래 실행할 수 있다. 결국 디버거 사용에만 의존한다면 디버거 내에서 로드하자마자 TLS callback을 실행하므로 악성코드 기능을 놓칠 수 있다.

TLS는 데이터 객체가 자동 스택 변수가 아닌 윈도우 저장 클래스지만, 코드를 실행하는 각 스레드는 지역변수다. 기본적으로 TLS를 통해 각 스레드가 선언한 변수에 다른 값을 유지할 수 있다. 실행 파일에서 TLS를 구현할 때 일반적으로 아래의 그림과 같이 .tls 섹션에 위치해 있는 것을 확인할 수 있다. 윈도우는 정상적인 프로그램 코드 실행 전에 TLS CallBack 함수를 실행한다.


일반적인 프로그램들은 .tls 섹션을 사용하지 않기 때문에 .tls 섹션을 발견할 경우 가장 먼저 안티디버깅을 의심해야 한다. 위회의 방법으로는 OllyDbg의 경우 디버깅 옵션에서 Event 항목을 보면 Make first pause at: 이 존재하는 것을 확인할 수가 있다. 여기서 우린 System breakpoint로 설정을 해주면 TLS Callback이 실행되지 않고 그 전에 멈추므로 분석이 가능해진다.


Using Exceptions

예외 처리는 디버거를 방해하거나 탐지하는데 사용할 수 있다. 대다수 예외 기반 탐지 방식은 디버거가 예외 상황 발생후의 처리를 위해 디버깅중인 프로세스에게 즉각적으로 전달하지 못한다는 사실에 기반을 둔다. 대부분 디버거의 기본설정은 예외를 처리하기 위해 예외를 프로그램에 전달하지 않게 설정한다. 디버거가 즉각적으로 프로세스에게 예외를 전달하지 않는다면 프로세스 예외 처리 메커니즘이 해당 오류를 탐지할 수 있다. 

* SEH는 FS : [0x0]에서 참고한다.


Inserting Interrupts

안티디버깅의 전형적인 형태는 예외를 발생시켜 분석가를 귀찮게 하거나 유효한 명령어 중간에 인터럽트를 삽입해서 정상적인 프로그램 실행을 방해한다. 디버거 설정에 따라 다르겠지만, 인터럽트 삽입은 디버거가 자체적인 소프트웨어 BP 설정과 동일한 메커니즘이기 때문에 이를 통해 디버거를 중단시킬 수 있다.

· INT 3 삽입

디버거는 INT 3을 이용해 소프트웨어 BP를 설정하므로 디버거가 해당 OPcode를 BP라 생각하게 유효한 코드 섹션에 0xCC OPcoe를 삽입하는 방식으로 안티디버깅을 구성한다. 2 바이트 옵코드 0xCD03 시퀀스 또한 INT 3 생성에 사용한다. 이는 WinDBG를 방해할 목적으로 악성코드가 자주 사용하는 유효한 방식이다. 디버거 외부에서 0xCD03은 STATUS_BREAKPOINT 예외를 발생시킨다. 그러나 WinDBG 내부에서 일반적으로 BP는 OPcode가 0xCC이므로 BP가 걸리면 그냥 EIP를 정확히 1바이트 증가시킨다. 이는 WinDG로 프로그램을 디버깅 중일때와 정상적으로 실행할 때 서로 다른 명령어 집합을 실행하게 한다.

· INT 2D 삽입

INT 2D 안티 디버깅 기법은 INT 3과 동일한 기능을 하며, INT 0x2D 명령어는 커널 디버거 접근에 사용한다. INT 0x2D는 커널 디버거가 BP를 설정하는 방식이다.

· ICE 삽입

Intel에서 문서화하지 않은 명령어 중 하나로 ICE(In-Circuit Emulator) BP인 icebp(OPcode:0xF1)가 있다. ICE를 이용해 임의의 BP를 설정하는 것이 어렵기 때문에 ICE에서 디버깅이 용이하게 icebp를 설계했다. icebp 명령어를 실행하면 싱글 스텝 예외가 발생한다. 싱글 스텝을 통해 프로그램을 추적하는 경우 디버거는 싱글 스텝이 생성한 일반적인 예외라고 여기고 이전에 설정한 예외처리를 실행하지 않는다. 악성코드는 정상적인 실행 흐름을 위해 예외 핸들러를 이용해서 이를 악용할 수 있는데, 이 경우 문제가 발생할 수 있다. 이런 기법을 우회하려면 icebp 명령어 실행 시 싱글 스텝을 사용하지 않으면 된다.



Debugger Vulnerabilities


모든 소프트웨어와 같이 디버거 자체에도 취약점을 갖고 있으므로 때때로 악성코드 제작자는 디버깅을 방지할 목적으로 이 취약점을 공격한다. OllyDbg가 PE 포맷을 처리하는 방식에서 잘 알려진 일부 취약점을 소개한다.

PE 헤더 취약점

이 기법은 OllyDBG가 실행 파일을 로드할 때 크래시되게 MS의 실행 가능 바이너리의 PE 헤더를 변조하는 방식이다. 이는 Ollydbg가 PE 헤더와 관련된 사항을 지나치게 엄격하게 따르는데 있다. IMAGE_OPTIONAL_HEADER로 알려진 전형적인 구조가 있다. 아래의 그림을 보자.

이 구조체에서 마지막 일부 요소를 주목해보자. NumberOfRvaAndSizes 필드는 바로 뒤따라오는 DataDirectory 배열의 Entry 개수를 나타낸다. DataDirectory 배열은 파일에서 다른 중요한 실행 요소를 찾기 위한 장소를 가리키고 있다. 하지만 위의 그림에선 이 수를 0x99로 설정하므로 존재하는 16개의 수를 넘는다. OllyDBG는 표준을 따르고 있기 떄문에 반드시 NumberOfRcaAndSizes를 사용한다. 결론적으로 0x99와 같이 0x10 보다 많은 값으로 배열의 크기를 설정했다면 OllyDBG는 실행전에 사용자에게 팝업 윈도우를 생성한다.

이 기법을 가장 쉽게 우회하는 방법은 해당 값을 수정하거나 OllyDBG 2.0 을 사용하는 것이다. 위의 취약점은 ollydbg 1.0에 해당하는 것이다.


섹션 헤더에 관련된 또 다른 PE 헤더 문제점은 OllyDbg가 로드하는 동안 'File contains too much data' 라는 에러와 함께 크래시된다. 각 섹션에는 코드, 데이터, 리소스와 기타 파일 정보가 담겨있다. 각 섹션은 IMAGE_SECTION_HEADER 구조체 형식으로 헤더를 갖고 있다. 위 그림이 이 구조체의 일부이다.

VirtualSize와 SizeOfRawData에 주목하자. 윈도우 로더는 메모리 내의 섹션 데이터를 매핑시키기 위해 더 작은 VirtualSize와 SizeOfRawData를 사용한다. SizeOfRawData가 VirtualSize보다 크다면 VirtualSize 데이터를 메모리에 복사하지만 나머지는 무시한다. 여기서 OllyDBG는 SizeOfRawData만을 사용하기 때문에 SizeOfRawData를 0x77777777처럼 큰 값으로 설정하면 OllyDbg가 크래시된다.

이러한 안티디버깅 기법을 우회하는 가장 손쉬운 방법은 수동으로 PE 헤더를 수정하거나 16진수 데이터를 사용해서 SizeOfRawData를 VirtualSize에 가까운 값으로 변경한다.



Conclusion


대중적인 안티디버깅 기법을 보았으며 이러한 기법을 익히고 인지해서 우회하기까지 인내가 필요하다. 대다수 안티디버깅 기법은 프로세스를 천천히 디버깅하는 과정 중에 상식선에서 발견할 수 있다. 대다수 대중적인 안티디버깅 기법은 FS:[0x30]에 접근해 윈도우 API를 호출하거나 시간을 검사하는 기법을 자주 사용한다.

물론 모든 악성코드 분석과 마찬가지로 안티디버깅 기법을 무산시키는 가장 좋은 방법은 계속해서 악성코드를 공부하고 역공학해보는 것이다.



요약


IsDebuggerPresent FS:[30] + 2    CheckRemoteDebuggerPresent FS:[30]+2    tQueryInformationProcess     OutputDebugString    FindWindow

FS:[30]+2    FS:[30]+18    FS:[30]+68

INT3 : 0xCC    0xCD    Checksum    rdtsc    QueryPerformanceCouter    GetTickCount    TLS    SEH : FS:[0]

INT 3    INT 2D    ICE

'Reversing > Theory' 카테고리의 다른 글

Contents of the TIB (32-bit Windows)  (0) 2015.09.04
Anti Virtual Machine  (0) 2015.09.03
Anti disassembly  (0) 2015.09.01
DLL Injection  (0) 2015.08.29
데이터 인코딩  (0) 2015.08.26

Anti disassembly

Kail-KM
|2015. 9. 1. 03:26

Understanding Anti Disassembly


안티 디스어셈블리 구현 시 악성코드 제작자는 디스어셈블러를 속여 실제 실행과 다른 명령어들의 목록을 디스어셈블러에 보이게 일련의 과정을 생성한다. 안티 디스어셈블리 기법은 디스어셈블러의 가정과 제약 사항을 이용한다. 예를 들어 디스어셈블러는 한번에 명령어 하나로 프로그램의 각 바이트를 표현하지만 이러한 잘못된 오프셋에서 디스어셈블하게 교묘히 조작하면 유효한 명령을 화면에서 숨길 수 있다. 아래의 코드를 살펴보자.


이 코드는 IDA Pro로 확인했을 경우에 보이는 코드이다. 40100E의 위치에 있는 JZ 401011 명령어가 존재하고 있다. 하지만 디스어셈블러는 401010의 명령어를 보여주며 심지어 잘못된 주소를 호출하고자 하는 것을 확인할 수가 있다. 이제 이룰 수정한 아래의 코드를 보자.

이전의 코드와는 다르게 40100E의 JZ 명령어가 올바른 곳을 가리키고 있는것을 확인할 수가 있다. 이는 401010의 위치에 0xE8 이라는 값이 존재하기에 디스어셈블러에서 잘못 나타나게 된 것이다.여기서 0xE8은 CALL 명령어의 OPCODE로 0xE8까지 같이 인식이 되었기에 잘못된 주소를 호출하고자 한 것이다.


*OllyDBG의 경우 저 부분은 올바르게 인식을 했지만 다른 부분을 올바르게 인식하지 못하였다. 그러므로 하나의 디스어셈블러에만 의존하는 것은 자칫 오류를 범할 수가 있다.


아래는 CALL 명령어 뒤에 "hello"라는 문자열이 존재하는 경우이다. 원래의 경우라면 hello라는 문자열은 호출되지 않으므로 아무 이상없어야 한다. 하지만 아래 그림 에서와 같이 Call 명령어 뒤에 PUSH 명령어가 존재하는 것을 확인할 수가 있다. 이는 "h"에 해당하는 0x68이 PUSH의 OPCODE이기에 push는 하나의 오퍼랜드를 필요로 하기에 뒤에 4바이트가 push의 오퍼랜드로 인식이 되어 맨 뒤의 0x00은 그 뒤의 명령어들과 짝을 이루어 나타나게 된다.

이를 정상적으로 나타내도록 수정하면 아래와 같이 'hello' 문자열이 나타나고 pop eax 와 retn 명령어가 제대로 나타나는 것을 확인할 수가 있다.



Anti-Disassembly Techniques


디스어셈블러가 부정확하게 디스어셈블하게 하는 악성코드의 주요 방법은 디스어셈블러의 선택과 가정을 악용하는 것이다. 이제 이러한 종류에 어떤 것들이 있는지 확인을 해볼 것이다. 


Jump Instructions with Same Target

이러한 방법 중 하나인 동일한 대상으로 점프하는 명령어에 대하여 알아보면 아래의 명령어와 같다. 이는 두 조건 분기 명령어가 연달아 두 개 모두 같은 지점을 가리키는 형태다. 이는 실제로 JMP 명령어와 다를 바가 없지만 디스어셈블러는 이 명령어를 올바르게 인식하지 못한다.

위에서는 call 명령어가 잘못된 주소를 가리키고 있는 것을 확인할 수가 있다. 이에 대하여 우리는 수정을 하여 아래와 같이 나타낼 수가 있다. 실제로 두개의 조건 분기들은 모두 올바르게 가리키고 있는 것을 확인할 수가 있다. 여기서 우리는 IDA를 통하여 잘못된 주소를 가리키는 부분이 붉게 표시되는 것을 확인할 수가 있는데, 이 표식은 현재 분석하고 있는 파일이 안티디스어셈블리 기법이 적용됐을 가능성을 나타내는 단서 중 하나이다.


A Jump Instruction with a Constant Condition

위와 유사하게 찾을 수 있는 또 다른 안티디스어셈블리 기법은 항상 동일한 조건으로 구성한 하나의 조건 분기 명령어를 이용하는 것이다. 다음 코드는 이 기법을 사용한다. 아래의 그림을 보면 xor eax, eax 명령어로 시작되는 코드를 주의해야 한다. 이 명령어는 EAX를 0으로 만들고 부가적으로 ZF를 설정한다. 이 다음 조건 분기 명령어인 JZ는 ZF가 설정되어 있을 때 분기를 한다.

디스어셈블러는 거짓분기를 우선 처리하면서 참일 때의 분기 구문과 충돌하게 되며 거짓 분기를 첫 번째로 처리하기 때문에 해당 분기를 더 신뢰한다. 아래의 그림을 보면 무조건 점프로 인하여 0xE9는 무시되어야 하자만 거짓 분기를 우선적으로 처리하므로 인하여 E9가 그 뒤의 바이트 까지 오퍼랜드로 이용을 한다는 것이다.

이를 정상적으로 수정하면 아래와 같이 표시가 된다. 여기서도 우리는 올바르지 않은 주소로 점프하려하는 것을 확인할 수가 있었고 이를 단서로 안티 디스어셈블리 기법을 의심할 수가 있다. 아래에는 0xE9가 하나의 Byte로 존재하며 그 뒤의 pop eax와 retn이 올바르게 나타나 있다.


Impossible Disassembly

위에서는 디스어셈블러가 부적절하게 디스어셈블한 코드를 살펴보았다. 그러나 단일 바이트를 두 명령어의 일부로 표현하는 디스어셈블러는 현재 존재하지 않지만 프로세서는 단일 바이트를 다중 명령어로 사용되지 못하게 하는 제약이 없다.

아래의 그림을 보면 첫 번째 명령어는 4바이트의 mov 명령어이다. mov의 마지막 2 바이트는 mov 명령어의 일부이면서 나중에 실행할 명령어 자체이기도 하다. 두번째 명령어인 xor 은 레지스터를 0으로 만들고 ZF를 설정한다. 세번째 명령어는 조건 분기로 ZF가 설정돼 있을 경우 분기한다. 하지만 직전 명령어가 항상 ZF를 설정하므로 실제론 무조건 분기라고 할 수 있다. 디스어셈블러는 jz 명령어 다음에 0xE8로 시작하는 5바이트의 call 명령어의 디스어셈블 여부를 결정한다. 하지만 실제로 이 0xE8은 실행되지 않는 가짜 바이트이며 그 다음 부분이 실제로 실행될 부분이다.



Obscuring Flow Control


Return Pointer Abuse

아래의 코드를 살펴보면 call 명령어가 바로 뒤의 add 명령어를 인식한다. 하지만 add의 오퍼랜드는 IDA에서 인식한 것으로 항상 정확하지는 않다. ESP+4+var_4에서 var_4는 상수로 -4를 이야기하는 것이다. 이는 즉, ESP+4+(-4)이므로 ESP를 기리키게 되는데 이 ESP에 +5를 더하는 것이다. 이로 인하여 스택의 ESP에 위치한 RETN 주소(4011C5)에 5를 더하게 되므로 이는 결국 4011CA를 기리키게 되며 이 주소로 다음 명령어에 의해 이동하게 된다.

이는 가짜 RETN을 통하여 그 부부능로 이동하는 것이라 할 수 있다. 이 예제에서는 위의 명령어 3개를 NOP으로 수정하여 정상적으로 패치할 수가 있다.


Misusing Structured Exception Handlers [ SEH ]

SEH 메커니즘은 디스어셈블러로 따라갈 수 없게끔 디버거를 속여 흐름을 제어하는 방법을 제공한다. SEH는 프로그램이 지능적으로 에러 상황을 처리할 수 있는 방식을 제공한다. 우선 유효하지 않은 메모리에 접근하거나 0으로 나누는 겨우와 같이 다양한 이유로 Exception이 발생할 수 있다. 이에 추가적으로 소프트ㅜ에어 예외 처리는 RaiseException 함수를 호출함으로 발생할 수 있다.

SEH chain은 스레드 내에서 예외 처리를 목적으로 고안한 함수 목록이다. 목록 내의 각 함수는 예외를 처리하거나 목록 내의 다음 핸들러에게 넘길 수 있다. 예외가 최정 핸들러까지 넘어간 경우 처리 불가 예외(Unhacndled exception)로 간주한다.

SEH 체인을 찾으려면 운영체제는 FS 세그먼트 레지스터를 확인한다. 이 부분은 TEB로 스레드 환경블록이라 하며 이에 접근하기 위해 사용 되는 것이 FS 이다. TEB에 있는 첫번째 구조는 스레드 정보블록 TIB이다. 이 TIB의 첫번째 항목이 SEH 체인을 가리키는 포인터이다.SEH Chanin은 EXCEPTION_REGISTRATION 레코드라 부르며 8바이트 데이터 구조의 단순 연결 리스트이다.

SEH 체인은 프로그램의 변화 속에서 서브루틴을 호출하거나 예외 핸들러 블록을 삽입하기 때문에 예외 처리 핸들러가 스택과 같이 동작하며 예외가 발생할 때 가장 먼저 ExceptionHandler 함수를 호출한다. 이는 MS의 소프트웨어 DEP ( Data Execution Prevention)라는 메커니즘에 의해 부과된 제약조건이 적용된다.


Conclusion


현대 디스어셈블러와 같은 고급 프로그램은 명령어가 구성하는 프로그램을 결정하는 작업을 훌륭하게 수행하지만, 디스어셈블러는 여전히 가정 사항을 필요로하고, 프로세스에서 선택해야하는 문제가 있다. 디스어셈블러가 선택하고 가정하는 각각에 대응하는 안티디스어셈블리 기술이 있을 수 있다.


'Reversing > Theory' 카테고리의 다른 글

Anti Virtual Machine  (0) 2015.09.03
Anti Debugging  (0) 2015.09.03
DLL Injection  (0) 2015.08.29
데이터 인코딩  (0) 2015.08.26
위장 악성코드 실행  (1) 2015.08.24

DLL Injection

Kail-KM
|2015. 8. 29. 04:16

'Reversing > Theory' 카테고리의 다른 글

Anti Debugging  (0) 2015.09.03
Anti disassembly  (0) 2015.09.01
데이터 인코딩  (0) 2015.08.26
위장 악성코드 실행  (1) 2015.08.24
Malware Behavior ( 악성코드의 행위 특성 )  (0) 2015.08.20

데이터 인코딩

Kail-KM
|2015. 8. 26. 01:54

악성코드 분석 과정에서 데이터 인코딩이란 의도를 숨길 목적으로 내용을 수정하는 모든 형태를 말한다. 즉, 악성코드는 악의적인 행위를 숨기기 위해 인코딩 기법을 사용하므로, 악성코드 분석가로서 악성코드를 완전히 이해하기 위해 이런 기법들을 이해해야 한다.


인코딩 알고리즘 분석의 목적


악성코드는 인코딩을 다양한 목적으로 사용하는데 일반적으로 네트워크 기반 통신의 암호화를 위해 사용한다. 악성코드는 내부 작업을 숨기기 위해서도 인코딩을 사용한다. 예를 들어 다음과 같은 목적으로 인코딩을 할 수 있다.

- C&C 도메인 같은 설정을 숨기기 위하여

- 정보를 훔치기 전에 임시 파일에 저장하기 위하여

- 악성코드에서 사용하는 문자열을 저장하고 사용하기 전에 디코딩하기 위해

- 악의적인 활동에 쓰이는 문자열을 숨김으로써 악성코드를 정상적인 도구로 가장하기 위해


단순 암호화


단순 인코딩 기법은 사람이 읽지 못하게 변경하거나 데이터를 다른 문자셋으로 전환하기 위한 데이터 변경에 자주 사용된다. 단순 암호화는 정교하지 않아 자주 가치가 없다고 간주되지만, 다음과 같이 악성코드에 이점을 제공한다.

- Exploit Shell Code 같은 공간 제약이 있는 환경에 사용할 수 있을 만큼 충분히 작다.

- 더 복잡한 암호화보다 덜 명확하다.

- 부하가 적게 발생하기 때문에 성능에 미치는 영향이 작다.


시저 암호

초기 암호 중 하나가 바로 Caesar Cipher이다. 시저 암호는 알파벳을 오른쪽으로 3문자를 옮기는 단순 암호다. 

ATTACK AT NOON 

 DWWDFN DW QRRQ



XOR

XOR 암호는 시저 암호와 유사한 단순 암호다. XOR 암호는 고정된 바이트 값을 사용해 논리적 XOR 연산을 함으로써 평문의 각 바이트를 변경한다. 여기선 하나의 기준 값이 주어져야 하는데 바로 어떠한 값과 XOR 연산을 할 것인가이다. 아래는 0x3C와 XOR 암호화를 진행한 것을 보여준다.

0x41 0x54 0x54 0x41 0x43 0x4B 0x20 0x41 0x54 0x20 0x4E 0x4F 0x4F 0x4E (ATTACK AT NOON )

0x7D 0x68 0x68 0x7D 0x7F 0x77 0x1C 0x7D 0x68 0x1C 0x72 0x71 0x71 0x72                        

여기선 문자로 출력이 불가능한 문자들을 포함하기도 한다. 이렇게 XOR 암호는 단 하나의 머신 코드만을 필요로 하기 떄문에 간단하고 양방향성을 갖고 있기 떄문에 편리하다고 할 수 있다. 또한 양방향 암호는 인코딩과 디코딩에 동일한 함수를 사용하므로 디코딩을 할 때에도 동일한 키를 가지고 XOR 연산을 시행하면 된다.




무차별 대입 XOR 인코딩

악성코드 분석을 진행 중이라 가정할 때 리소스 섹션에 아래와 같은 Hex 값이 존재한다고 가정하자. 리소스 섹션은 주로 프로그램의 실행에 필요한 이미지나 아이콘 같은 정보들을 포함하기도 하지만 별도의 EXE나 DLL을 리소스 섹션에 포함하고 있을 수가 있다. 여기서 우리는 Resource Data Entry에 따른 위치에 아래의 값이 있을 경우 많은 부분이 0x50('P')로 되어 있는 것을 확인할 수가 있다. 이를 통하여 0x00이어야 할 부분이 0x50이라고 의심할 수가 있다. 

하지만 조금 더 확실한 단서들을 알아보자면 윈도우에서 EXE나 DLL이 내장되어있으므로 00000000~00000001 부분에 "MZ"가 나타나야 한다. 위에선 첫 바이트가 0x1D 이므로 "M"의 값인 0x4D와 XOR을 하면 해당 키를 알아낼 수가 있다. 이렇게 XOR 연산의 경우 인코딩이 되었다는 것을 인지만 하면 디코딩 또한 간단하다.


NULL Byte 보존 XOR 인코딩

위의 예에서는 너무나 많은 0x50 값으로 인하여 쉽게 XOR 인코딩을 알아낼 수가 있었다. 여기서 악성코드 제작자는 NULL-Preserving 단일 바이트 XOR 인코딩 구조를 이용해 이 문제를 해결할 수가 있다. 일반적인 XOR 인코딩 구조와 달리 널 보존 단일 바이트 XOR 구조는 2가지 예외를 가진다.

- 평문 문자가 NULL이거나 키일 경우에는 해당 바이트는 지나친다.

- 평문 문자가 NULL 또는 키가 아닌 경우에는 키와 더불어 XOR 연산을 통해 인코딩 한다.

아래의 사진 2장을 보면 .docx 확장자이다. 맨앞에 PK가 존재하는데 여기선 NULL 과 키 값을 보존하기 위하여 널 보존 단일 바이트 XOR 인코딩을 진행하였다. 그 결과 두 번쨰 사진과 같이 0x50('P')와 0x00(NULL)이 보존되어있으므로 인코딩을 알아차리기가 위의 예에 비하여 어렵다. 또한 여기서 우리는 확장자가 .docx라는 것을 알고 있기에 키 값을 찾는 것이 쉬웠지만 만약 어떠한 파일이 리소스 섹션에 포함되었는지를 알지 못할 경우 각 파일의 구조와 직접 비교하여 키 값을 찾아내어야 어떠한 파일인지 확인할 수가 있다.

XOR 반복문 파악

인코딩 되어 있는 프로그램의 경우 상세 분석을 통하여 쉽게 프로그램의 디코딩 과정을 찾을 수가 있다. 인코딩된 프로그램의 경우 그 자체 그대로 실행을 할 경우 명령어가 망가져있기 떄문에 보통 프로그램이 메모리에 로드되고 명령어의 초반 부분에 디코딩 루프가 존재하고 있다. 아래는 ap0x patch me1 문제로써 아래와 같은 디코딩 루프가 여러 곳에 존재한다.

굳이 XOR 연산을 한번만 하는 것이 아니라 여러번에 걸쳐서 좀 더 복잡하게 만들 수가 있다. 이러한 디코딩 루프는 OllyDBG나 IDA를 통하여 살펴보면 반복되는 구간으로 인하여 그나마 쉽게 찾을 수가 있다. 아래는 인코딩된 문자열이 디코딩 루프를 걸쳐서 디코딩된 문자열이 되고 그 다음에 그 명령어들이 실행이 되는 일반적인 과정을 간략하게 그린 것이다.

* 추가로 인코딩되어 있어 직접적인 패치가 어려울 경우 수행하는 방법으로 Code Cave가 있다. 코드 케이브는 디코딩이 끝난 후 OEP로 점프하기 이전에 코드 케이브라는 영역을 만들어 그 부분으로 점프하게하며 그 코드케이브는 인코딩의 영향을 받지 않는 섹션이나 위치에 형성해야한다. 코드 케이브영역에는 인코딩 영역의 문자열을 패치하는 명령어들을 만들어 간접적인 패치를 쉽게 할 수 있게 도와준다.




다른 간단한 인코딩 구조


단일 바이트 인코딩의 약점을 감안해서 대부분의 멀웨어 코더들은 좀 더 진화된 인코딩 구조를 구현한다. 

인코딩 구조 

설명 

ADD, SUB 

 인코딩 알고리즘은 개별 바이트에 대해 XOR 과 유사한 방법으로 ADD와 SUB를 사용할 수 있다. ADD와 SUB는 양방향성이 아니므로 하나는 인코딩을 위하여 다른 하나는 디코딩을 위하여 함께 사용해야 한다.

ROL, ROR 

 명령어는 바이트를 오른쪽이나 왼쪽으로 순환시킨다. ADD 와 SUB와 동일하게 양방향성을 갖지 못했기 때문에 이들 명령어는 함께 사용되어야 한다.

ROT 

 ROT는 원래의 시저 암호다. 일반적으로 알파벳 문자 또는 ASCII 에 있는 94개의 출력 가능 문자를 사용한다.

Multibyte 

 단일 바이트 대신 알고리즘은 긴 키(4 or 8 Byte )를 사용할 수 있다. 일반적으로 편의를 위해 각 블록에 대해 XOR을 사용한다.

Chained or loopback 

 이 알고리즘은 다양한 구현과 더불어 데이터 자체를 키의 일부로 사용한다. 거의 대부분 원본 키는 일반 텍스트의 한 측면에 적용되고, 인코딩된 결과 문자는 다음 문자의 키로 사용된다. 


Base64

Base64 인코딩은 바이너리 데이터를 ASCII 문자열 포멧으로 나타낼 때 사용하며 악성코드에서 흔히 발견할 수 있기 때무에 Base64를 인지하는 방법을 알고 있어야 한다. Base64라는 단어는 다목적 인터넷 메일 확장(MIME) 표준에서 나왔으며 원래는 이메일 첨부 파일의 전송을 위한 인코딩으로 개발됐지만, 현재는 HTTP와 XML을 위해 널리 사용된다.

Base64 인코딩은 바이너리 데이터를 제한된 64개의 문자 집합으로 변환한다. 다른 종류의 Base64 인코딩을 위한 다수의 구조와 알파벳이 있다. 이들 모두는 64개의 주요 문자를 사용하고 패딩을 나타내기 위한 추가 문자로 =를 자주 사용한다.

인코딩되는 방식은 나름 표준적이라 할 수가 있다. 3Byte의 문자 블럭을 사용한다. 위에서는 'M', 'a', 'n'을 예로 들고 있다. 이렇게 제시된 문자들의 아스키 값을 2진수로 나타내면 총 24조각으로 나누어 진다. 이렇게 나누어진 블럭을 6비트씩 읽어들인다음 아래의 Index Table에 따라 해당 값을 찾는다. 이렇게 총 24블럭을 6개씩 나누므로 4개의 문자가 나온다.

디코딩 또한 동일 프로세스를 역으로 실행하면 된다. 다시 말하자면 Base64 문자를 6비트로 변환하고 모든 비트를 순서대로 나열한 다음에 8비트씩 그룹 지으므로 총 3개의 그룹으로 나누어 지며 그에 해당하는 ASCII를 찾으면 해당 문자를 복원할 수가 있다.

* 악성코드가 문자열로 A~Z + a~z + '+' , '/'을 포함할 경우 이는 Base64 테이블이므로 인코딩을 의심해보아야 한다. 분명 어느 위치를 계속 참조할 것이다. 그 부분을 찾아야 한다.


일반 암호화 알고리즘


치환 암호와 동일한 단순 암호 구조는 현대 암호학의 암호와 매우 다르다. 현대 암호학은 기하급수적으로 증가하는 계산 능력을 요구하며, 알고리즘은 너무 많은 계산 능력을 필요로 하기 때문에 해당 암호를 깨는 것은 비실용적이 되도록 설계 됐다. 이전의 단순 암호 구조는 무차별 대입에 대한 보호조차 존재하지 않고 단순히 이해를 어렵게 하는 것이 목적이다. 암호학은 많은 부분에서 진화했지만 악성코드에 있어서 자신의 정보를 숨기기 위해 이러한 고도의 암호학을 활용하지 않는 이유 또한 존재한다. 이유는 다음과 같다.

- 암호 라이브러리는 크기가 클 수 있으므로, 악성코드는 정적으로 코드에 통합시키거나 기존 코드에 링크할 필요가 있다.

- 호스트의 기존 코드에 크드를 링크하는 것은 휴대성을 떨어뜨릴 수 있다.

- 표준 암호 라이브러리는 쉽게 탐지된다.

- 대칭 암호 알고리즘은 암호키를 숨기는 방법에 대해 걱정할 필요가 있다.

다수의 표준 암호 알고리즘은 강력한 암호 키에 의존해 비밀을 저장한다. 암호 알고리즘 자체는 널리 알려지더라도 암호문을 복호화하는 것은 다량의 계산을 요구하기 떄문에 거의 불가능하다는 개념이다. 복호화에 걸리는 충분한 계산량을 보장하기 위해 암호 키는 가능한 모든 키를 쉽게 테스트할 수 없게 충분히 길어야 한다. 또한 악성코드가 사용할 수 있는 표준 알고리즘에 대해서는 알고리즘 뿐만 아니라 키까지 식별할 수 있다는 점이 핵심이다.

표준 암호의 사용을 식별할 수 있는 몇가지 쉬운 방법으로는 암호 함수가 참조하는 문자열과 임포트에 대한 검색과 특정 내용을 검색하기 위한 몇 가지 도구의 사용을 포함 한다.


문자열과 임포트 식별

표준 암호 알고리즘을 식별하는 한 가지 방법은 암호 사용에 참조하는 문자열과 임포트를 찾아 내는 것이다. 해시, 키 생성, 암호와 관련된 서비스를 제공하는 일부 암호 임포트 목록들이 있는데 이러한 암호화 관련된 API 함수 대부분은 Crypt, CP, Cert로 시작한다.


암호 상수 검색

암호 탐지의 세 번째 기본 방법은 일반적으로 사용되는 암호 상수를 검색할 수 있는 도구를 사용하는 것이다. 이러한 도구로는 IDA Pro의 FindCrypt2와 Krypto ANALyzer가 있다.


하이 엔트로피 콘텐츠 검색

암호 사용을 식별할 수 있는 다른 방법은 하이 엔트로피 콘텐츠를 검색하는 것이다. 암호 사용의 가능성으로 암호 상수나 암호 키를 가종하는 것 외에도 이 기법은 암호화된 내용 자체도 식별할 수 있다. 이 기법의 광범위한 범위로 인해 RC4 같이 암호 상수가 발견되지 않는 경우에 적용할 수 있다. 하지만 하이 엔트로피 콘텐츠 기법은 정확성이 떨어지므로 최후의 수단으로 사용하는 것이 좋다. 사진, 영화, 음성 파일, 압축 데이터 같은 다양한 유형의 콘텐츠는 엔트로피가 높게 표현된다. 따라서 헤더를 제외하고는 암호화된 내용과 구별하기 어렵다.



사용자 정의 인코딩


악성코드는 종종 자신만의 인코딩 구조를 사용한다. 그런 구조 중 하나는 여러 단순 인코딩 메소드 계층을 두는 것이다. 예를 들어 악성코드는 XOR 암호화를 한 라운드 수행한 후 결과를 Base4 인코딩할 수 있다. 다른 유형의 구조는 단순히 표준 게시 암호 알고리즘과 유사성을 가진 사용자 정의 알고리즘을 개발한다.


사용자 정의 인코딩 파악

쉽게 식별 가능한 문자열이나 상수를 사용할 때 악성코드에 있는 일반 암호 기법과 인코딩 함수를 식별하는 여러 방법을 설명했다. 대다수의 경우 이미 언급된 기술을 통해 사용자 정의 암호화 기법을 찾는 데 도움을 받을 수 있다. 하지만 명확한 증거가 없는 경우 식별하는 것이 어려워질 수 있다.

하지만 대부분의 경우 복호화 함수는 입력 함수에서 그리 멀리 떨어져 있지 않다. 결과 함수 역시 실행 흐름의 반대 방향으로 추적한다는 점을 제외하고는 유사하다. 이를 유념하고 상세 분석을 진행하다보면 복호화된 문자열을 쉽게 찾을 수가 있다.


사용자 정의 인코딩이 공격자에게 주는 이점

공격자에게 사용자 정의 인코딩 기법은 이점을 가진다. 단순 인코딩 구조의 장점인 작은 크기와 암호 사용의 불확실성을 유지하면서도 역공학 작업은 더 어렵게 한다. 다양한 종류의 표준 암호 기법의 경우 암호 알고리즘이 파악되고 키를 찾았다면 표준 라이브러리를 이용한 디코더 제작은 매우 쉬운 일이다. 

사용자 정의 인코딩을 이용하면 공격자는 자신이 원하는 임의의 인코딩 구조를 생성할 수 있다. 키를 코드 자체에 효과적으로 이식해 숨기 수도 있으며 공격자가 키를 사용했고 그 키가 발견됐다고 하더라도 복호화를 도와줄 수 있는 라이브러리를 쉽게 구하기 어렵다.



디코딩


인코딩 함수를 분리하기 위한 탐색도 분석 과정에서 중요하지만, 숨겨진 내용을 디코딩하는 것도 중요하다. 악성코드에서 인코딩이나 디코딩을 재현할 수 있는 두 가지 기본적인 방법이 있다.

- 해당 함수를 다시 프로그램하는 방법

- 악성코드 자체에 있는 것처럼 해당 함수를 사용하는 방법


셀프 디코딩

알고리즘의 인지 여부에 상관없이 데이터를 복호화하는 가장 경제적인 방법은 프로그램 자체적으로 일반적인 처리과정의 일환으로 복호화를 수행하는 것이다. 이런 프로세스를 셀프 디코딩이라고 한다. 디버거를 이용해 악성 프로그램을 중지한 후 메모리에서 실행하기 전에 보지 못했던 문자열을 파악했다면 이미 셀프 디코딩 기법을 사용한 것이다. 이는 디코더를 만드는 것보다 효율적이다.

하지만 셀프 디코딩이 콘텐츠를 디코딩하는데 저렴하고 효과적인 방법일 수 있지만 단점이 있다. 우선 복호화를 수행하는 모든 인스턴스를 파악하기 위해서는 복호화 함수를 구분할 수 있어야 하고, 복호화 루틴 이후 직접적으로 BP를 설정해야 한다. 더 중요한 점은 악성코드가 알고자 하는 정보를 복호화하지 않거나 악성코드가 어떤 방법으로 정보를 다루는지 파악하지 못한 경우 정보를 얻을 수 없다는 사실이다. 이런 이유들로 인해 통제가 가능한 기법을 사용하는 것이 중요하다.


디코딩 함수의 별도 프로그래밍

단순 암호와 인코딩 방법에 대해 프로그래밍 언어에서 제공하는 표준 함수를 이용할 수 있다. 아래는 표준 Base64 인코딩 문자열을 디코딩하는 작은 파이썬 프로그램을 보여준다. 관심 문자열을 디코딩하기 위해 example_string으로 변수를 변경한다.

변형된 알파벳을 사용하는 XOR 인코딩이나 Base64 인코딩 같이 표준 함수가 없는 단순 인코딩 방법의 경우 가장 쉬운 선택은 자신과 친숙한 프로그래밍 언어로 인코딩 함수를 프로그래밍하거나 스크립트를 작성하는 것이다. 아래는 위에서 설명했던 NULL 보존 XOR 인코딩을 구현하는 파이썬 함수의 예를 보여준다.

위의 함수는 다른 곳에서 읽은 self.data의 값을 가지고 xor 연산을 진행하는 것을 확인할 수가 있다. 이렇게 XOR 연산을 진행할 때 키 값인 0x50과 NULL인 0x00은 쉽게 인지되는 것을 방지하기 위하여 널 보존 XOR 인코딩을 수행하고 있는 것이다. 


일반 복호화를 위해 명령어 사용

셀프 디코딩에서 악성코드를 통해 복호화를 하려면 악성코드가 정상적으로 실행된 후 적절한 시점에 정지시켜야 한다. 하지만 악성코드의 복호화를 통제할 수 있다면 악성코드의 일반 실행 과정에 제한될 필요가 없다. 인코딩 루틴이나 디코딩 루틴이 분리되고 파라미터가 이해되면 악성코드에서 사용한 악의적인 콘텐츠를 디코딩하는데 완전하게 활용 가능할 수 있다. 따라서 효과적으로 악성코드를 이용해 악성 코드를 분석할 수 있다.

암호화된 파일(악성코드 자체)과 암호화 함수가 어떻게 동작하는지에 대한 지식을 갖고있다. 높은 수준의 목표는 암호화된 파일을 이용해 암호화에 사용된 동일한 루틴을 통해 실행할 수 있게 악성코드를 다루는 것이다. 높은 수준의 목표는 다음과 같은 일련의 작업으로 나눌 수 있다.

1. 디버거에서 악성코드를 설정한다. 

2. 읽기 위한 암호화된 파일을 준비하고 쓰기 위한 결과 파일을 준비한다. 

3. 악성코드가 메모리를 참조할 수 있게 디버거 내부에서 메모리를 할당한다. 

4. 할당된 메모리 영역으로 암호화된 파일을 로딩한다. 

5. 암호화 함수를 위한 적절한 변수와 인자와 더불어 악성코드를 설정한다. 

6. 암호화를 수행하기 위해 암호화 함수를 실행한다. 

7. 새롭게 복호화된 메모리 영역을 결과 파일에 쓴다. 



정리


악성코드 제작자와 악성코드 분석가 모두 지속적으로 자신의 능력과 기술을 개선하고 있다. 탐지를 회피하고 분석가를 좌절시키기 위해 악성코드 제작자는 자신의 의도, 기술과 통신 내용을 숨길 수 있게 다양한 방법을 지속적으로 사용한다. 이런 의도의 기초 도구는 인코딩과 옴호화다. 인코딩은 통신 그 이상의 영향을 끼친다. 다행히도 적절한 도구와 기법을 이용해 비교적 쉽게 파악하고 대응할 수 있다.





참고

https://en.wikipedia.org/wiki/Base64

https://www.base64encode.org/



실습


Lab13-1

1. 동적 분석을 통해 얻을 수 있는 정보와 악성코드에 있는문자열을 비교하자 비교를 바탕으로 어떤 요소가 인코딩됐는가?

www.practicalmalwareanalysis.com 라는 디코딩된 문자열을 찾을 수가 있다.


2. IDA를 사용해 문자열 xor을 탐색해 잠재적인 인코딩을 찾아보자. 어떤 유형의 인코딩을 발견했는가?

00401300 > 00401190


3. 인코딩에 사용하는 키는 무엇이며, 인코딩된 내용은 무엇인가?

4C 4C 4C 15 4B 49 5A 58 4F 52 58 5A 57 56 5A 57 4C 5A 49 5E 5A 55 5A 57 42 48 52 48 15 58 54 56

www.practicalmalwareanalysis.com


4. 정적도구를 사용해 그 외의 다른 인코딩 메커니즘을 파악해보자. 무엇을 찾았는가?

401000에도 디코딩루프가 존재하고있다.


5. 악성코드를 통해 전달되는 네트워크 트래픽을 위해 어떤 유형의 인코딩이 사용됐는가?


6. 디스어셈블리에서 Base64 함수는 어디있는가?


7. 전달되는 Base64 인코딩된 데이터의 최대길이는 무엇인가? 무엇이 인코드되는가?


8. 악성코드에서 Base64 인코딩된 데이터에서 패딩 문자(= or ==)를 본 적이 있는가?


9. 이 악성코드는 무엇을 하는가?


리소스 섹션에 무엇인가를 숨겨놓음

00000000603C   00000040603C      0   http://%s/%s/0000000056C8   

0000004056C8      0   InternetReadFile

0000000056DC   0000004056DC      0   InternetCloseHandle

0000000056F2   0000004056F2      0   InternetOpenUrlA

000000005706   000000405706      0   InternetOpenA

000000005714   000000405714      0   WININET.dll

000000004EDD   000000404EDD      0   ;=@n@

00000000604C   00000040604C      0   Could not load exe.
000000006060   000000406060      0   Could not locate dialog box.
000000006080   000000406080      0   Could not load dialog box.
00000000609C   00000040609C      0   Could not lock dialog box.


Address        Function   Instruction                      
-------        --------   -----------                      
.text:004011B8 sub_401190                 xor     eax, 3Bh 
.text:00402BE2                            xor     dh, [eax]
.text:00402BE6                            xor     [eax], dh


Lab13-2

1. 동적 분석을 이용해 악성코드가 무엇을 생성하는지 알아보자

이상한 temp 파일들을 생성한다.


2. xor 탐색 등 정적 분석 기법을 사용해 잠재적인 인코딩을 찾아보자. 무엇을 발견했는가?


3. 질문 1의 답을 바탕으로 어떤 임포트 함수가 인코딩 함수를 발견하는 데 좋은 힌트를 제공하는가?

BitBlt

FlushFileBuffers


4. 디스어셈블리에서 인코딩 함수는 어디에 있는가?


5. 인코딩 함수에서 인코딩된 컨텐츠의 근원을 추적해보자. 컨텐츠는 무엇인가?


6. 인코딩에 사용된 알고리즘을 찾을 수 있는가? 그렇지 못하다면 컨테츠를 어떻게 디코딩 할 수 있는가?


7. 지시문을 사용해 인코딩된 파일중 하나의 원본 소스를 복구할 수 있는가?


000000007030   000000407030      0   temp%08x

000000006724   000000406724      0   BitBlt
00000000662C   00000040662C      0   WriteFile
000000006638   000000406638      0   CreateFileA
Address        Function   Instruction              
-------        --------   -----------                  
.text:004012D6 sub_40128D xor     eax, [ebp+var_10]
.text:0040171F            xor     eax, [esi+edx*4] 
.text:0040176F sub_401739 xor     edx, [ecx]       
.text:0040177A sub_401739 xor     edx, ecx         
.text:00401785 sub_401739 xor     edx, ecx         
.text:00401795 sub_401739 xor     eax, [edx+8]     
.text:004017A1 sub_401739 xor     eax, edx         
.text:004017AC sub_401739 xor     eax, edx         
.text:004017BD sub_401739 xor     ecx, [eax+10h]   
.text:004017C9 sub_401739 xor     ecx, eax         
.text:004017D4 sub_401739 xor     ecx, eax         
.text:004017E5 sub_401739 xor     edx, [ecx+18h]   
.text:004017F1 sub_401739 xor     edx, ecx         
.text:004017FC sub_401739 xor     edx, ecx         
.text:0040311A            xor     dh, [eax]        
.text:0040311E            xor     [eax], dh        



Lab13-3

1. 정적분석을 통해 습득한 정보와 strings 결과를 비교하라 비교를 바탕으로 어떤 요소가 인코딩 됐는가?


2. 문자열 xor 탐색을 이용한 정적 분석을 통해 잠재적인 인코딩을 찾아보자 어떤 유형의 인코딩이 발견되는가?


3. FindCrypt2,KANAL,IDA 엔트로피 플로그인 같은 정적 도구를 사용해 다른 인코딩 메커니즘을 파악하자. 발견된 내용을 XOR 탐색과 어떻게 비교하는가?


4. 이 악성코드에 사용된 두 가지 인코딩 기법은 무엇인가?


5. 각 인코딩 기법에서 키는 무엇인가?


6. 암호화 알고리즘에 대해 키는 충분한가? 다른 어떤 것이 알려져야 하는가?


7. 이 악성코드는 무엇을 하는가?


8. 동적 분석 동안 생성된 컨텐츠의 일부를 복호화 하기 위해 코드를 작성하라. 이 컨텐츠는 무엇인가?

'Reversing > Theory' 카테고리의 다른 글

Anti disassembly  (0) 2015.09.01
DLL Injection  (0) 2015.08.29
위장 악성코드 실행  (1) 2015.08.24
Malware Behavior ( 악성코드의 행위 특성 )  (0) 2015.08.20
Code Virtualized - 코드 가상화 참고자료  (0) 2015.08.17