2016. 2. 11. 15:46

Chapter 49 IA-32 Instruction


Instruction이란 쉽게 말해서 CPU가 알아들을 수 있는 '기계어(Machine Language)'이다. IA-32 Instruction은 IA-32(Intel Architecture 32비트) 계열의 CPU에서 사용되는 Instruction을 말하는 것이다.


다음은 리버싱에서 자주 사용되는 용어이다.


C/C++(또는 어셈블리) 언어를 이용하여 PE(Portable Executable) 파일을 생성하면 소스코드는 기계어를 변환된다. 리버서는 이러한 기계어를 해석하여 동작원리를 파악하는 사람이다. 하지만 2진수로 표현된 기계어를 사람이 그냥 보는 것은 너무 힘든 작업이다. 그래서 보통 16진수로 변환해서 본다. 16진수로 보면 가독성은 좋아지지만, 아직 사람이 코드를 인식하기에는 무리가 있다. 그래서 최종적으로 (디버거에 탑재된) Disassembler를 이용하여 기계어를 디스어셈블리 코드로 변환한다.


다음은 여태 익히 보아오던 Ollydbg의 화면이다. Ollydbg에는 IA-32용 Disassembler가 탑재 되어있다.


위 그림을 보면 한줄에 하나의 명령어(Instruction)가 표시되어 있다. (A) 영역이 기계어로 표시된 IA-32 Instruction이다. 그리고 그에 해당하는 각각의 디스어셈블리 코드가 (B)에 나타나있다. 메모리(혹은 파일)에서는 실제로 (C)처럼 되어있다.


이런식으로 디버거에 탑재된 Disassembler는 (C) 영역의 Hex code를 해석하여 Instruction 단위로 쪼개서 표시(A)하고, 각 Instruction별로 디스어셈블리 코드(B)를 표시한다. 사람 눈으로 보기에는 C<A<B 순으로 보기 좋으며, 리버서들은 보통 (B) 형태의 디스어셈블리 코드를 보면서 분석을 수행한다. 


 Decompiler는 기본적으로 Disassembler와 같은 개념이다. 다만 Disassembler는 무조건 디스어셈블리 코드로 변환 해 주는데 반해, Decompiler는 원본 소스코드 형태로 변환 시켜주는 차이가 있다.(해당 언어제 맞는 Decompiler를 사용해야함). 물론 원본 소스코드와는 차이가 있으나 기술이 발전하면서 그 차이가 좁혀지고 있다.


위는 IDA Pro의 Hex-Rays Decompiler 플러그인을 사용하여 기계어 코드를 C언어로 해석한 것이다. 기계어 코드가 C언어 소스코드로 해석 되었음을 알 수 있다.


IA-32 Instruction 포맷은 다음과 같다.


위 그림처럼 총 6개의 항목으로 구성 되어있다. 여기서 Opcode 항목은 반드시 존재해야하며, 나머지 항목은 옵션이다. 이제 위 6가지 항목에 대하여 간단히 알아 볼 것이다.


1.Instruction Prefixes

 Instruction Prefixes는 옵션 항목으로, 뒤에 특정한 Opcode가 나올 때 사용되어 Opcede의 의미를 보조하는 역할을 합니다. 간단한 예는 다음과 같다.


Prefix 항목은 1바이트 크기를 가진다. 


 2.Opcode

 Opcode는 필수 항목이며 실제적인 명령어를 나타낸다.


Opcode는 1~3바이트 크기를 가진다. 일반적인 응용프로그램 디버깅에서 주로 1바이트 크기의 Opcode가 대부분이고 가끔 2바이트 크기의 Opcode들이 있다. 3바이트 크기의 Opcode도 있으나 접하는 경우가 거의 없다. Opcode는 보통 Operand를 갖는 경우가 많다. Operand의 종류는 Register, Memory Address, Constant 이다. 이러한 Opcode의 Operand를 결정하기 위해 보통 ModR/M과 SIB가 뒤따라오는 경우가 있다. Opcode는 그 종류가 매우 많이 때문에 일반적으로는 Intel Manual의 Opcode Map을 보면서 해석을 해야 한다.


 3.ModR/M

 ModR/M은 옵션 항목으로, 주로 Opcode를 도와서 Operand를 설명(Operand의 개수, 종류[Registers, Address, Contant])하는 수단으로 사용된다.


ModR/M은 1바이트 크기를 가지며 다음 그림과 같이 비트 단위로 분리되어 사용된다.


4.SIB

 SIB(Scale-Index-Base)는 옵션 항목으로, ModR/M을 보조할 때 사용된다. Opcode의 Operand가 Memory Address인 경우 ModR/M과 함께 사용된다.


SIB는 1바이트 크기를 가지며 ModR/M과 같이 비트 단위로 분리되어 사용된다.


 5. Displacement

 Displacement는 옵션 항목으로, Opcode의 Operand가 Memory Address인 경우 Displacement(변위)를 나타낼 때 사용된다. 


Displacement의 크기는 1,2,4바이트로 다양하다.


 6.Immediate

 Immediate는 옵션항목으로, Opcode의 Operand가 Constant인 경우에 그 Constant를 Immediate라고 말한다.

Immediate의 크기는 1,2,4바이트로 다양하다.



이제 본격적으로 바이너리 코드를 어셈블리로 해석하는 실습을 할 것이다. 실습에 앞서 바이너리 코드를 어셈블리로 해석하기 위해서는 IA-32 Instruction에 대한 정확한 이해가 필요하다. IA-32에 대한 설명은 제조사인 Intel에서 제공한 공식 매뉴얼에 자세히 설명되어있다. 


http://www.intel.com/products/processor/manuals


위 링크로 접속하여 아래 두 파일을 다운 받으면 된다.

 Intel@ 64 and IA-32 Architectures Software Developer’ s Manuals Volume 2A.pdf

 Intel@ 64 and IA-32 Architectures Software Developer’ s Manuals Volume 2B.pdf


이제 본격적으로 IA-32 Instruction을 해석 하는 방법에 대해 학습 할 것이다.


1.Opcode Map

첫 실습 예제로 1바이트 Opcode를 골랐다.

 41    INC ECX

앞에서 다운 받으라고 한 Opcode 매뉴얼(혹은 Intel Manual Vol. 2B)의 'Table A-2. One-byte Opcode Map'을 보면 된다.


Instruction을 해석 할 대 가장 먼저 확인해야 할 것이 바로 Table A-2 One-byte Opcode Map이다. 찾으려 하는 Opcode 41을 4와 1로 쪼갠 후 Opcode Map에서 각각 행과 열로 하여 찾으면 된다. 이 경우 명령어는 INC이며, Operand는 ECX로 고정된다.(REX.B는 64비트 전용이므로 무시한다.) 따라서 Instruction 41은 INC ECX 명령어를 의미한다. 이것을 위에서 설명했던 IA-32 Instruction Format으로 표시하면 다음과 같다.


2. Operand

 이번에는 Operand의 형태를 파악하는 연습을 해 볼 것이다.

68 A0B44000 PUSH 0040B4A0

앞에서와 같은 방법으로 Instruction의 첫바이트 68을 Table A-2 Opcode Map에서 찾는다.


 위 그림을 보면 Opcode 68은 PUSH Iz라고 표시되어 있다. 즉 Operand를 하나 가지는 PUSH 명령어이다.

Operand 타입을 나타내는 Iz의 의미를 알아야 정확한 해석이 가능하다. 대문자 I는 Addressing Method를 의미하고 소문자 z는 Operand Type을 의미한다. 이들은 각각 앞에서 만든 Opcode 매뉴얼의 A.2.1 Codes for Addressing Method과 A.2.2 Codes for Operand Type에 설명되어있다. 다음은 자주 사용되는 Addressing Method를 정리한 것이다.

 Addressing Method를 의미하는 대문자 I는 Immediate이다. 상수의 크기를 알려면 Operand Type을 참고해야 한다. 다음은 자주 사용되는 Operand Type을 정리 한 것이다.


Operand Type을 의미하는 소문자 z는 32bit 모드에서 DWORD(32bit) 크기이다. 따라서 이 모든 정보를 종합하면 Opcode 68은 PUSH Iz 명령어 형식이고, Operand 형식을 나타내는 Iz 기호는 4바이트(32비트) 상수를 의미하므로 68 뒤의 4바이트(0040B440)를 더 읽어서 최종적으로 PUSH 0040B4A0으로 해석이 된다. IA-32 Instruction Format으로 표시하면 다음과 같다.








'리버싱핵심원리' 카테고리의 다른 글

Reverse Engineering Chap 48  (0) 2016.02.03
Reverse Engineering Chap 47  (0) 2016.02.03
Reverse Engineering Chap 46  (0) 2016.02.03
Reverse Engineering Chap 50-51  (0) 2016.02.03
Reverse Engineering Chap 21-22  (0) 2016.02.03
Posted by 키흐
2016. 2. 3. 18:40

Chapter 48 SEH

48.1. SEH

EEH Windows 운영체제에서 제공하는 예외 처리 시스템입니다.

48.2. SEH예제 실습

먼저 한 간단한 예제를 통해 SEH의 기본 동작 원리와 안티 디버깅에서 SEH가 어떻에 사용되는지 살펴보겠습니다.

이 예제 파일을 실행해 보고 아래 그림과 같이 메지지 박스를 나왔습니다.

이 프로그램은 정상적으로 실행된 것처럼 보이지만 사실 프로세스 내부에서 예외가 발생했습니다. 그런데 SEH를 통해 예외가 잘 처리되어서 정상 실행될 수 있습니다.

이 파일을 디버깅하고 그대로 실행하면 아래 그림과 같이 예외가 발생하면서 실행이 중지되고 status창에서 경고문이 나타납니다.

401019주소에서 EAX 레지스터의 값은 0입니다. MOV DWORD PTR DS:[EAX], 1 명령어의 의미는 메모리 주소 0에 값1을 입력하는 것입니다. 그런데 주소 0이 할당되지 않은 공간인데 마음대로 접근할 수 없어서 예외가 발생했습니다.

그래서 Shift+f9 단축 키로 계속 진행해 보고 아래의 메시지 박스가 나타납니다.

이 메시지 박스를 보면 알 수 있는데 이와 아까 그냥 실행시켰을 때 나타난 메시지 박스가 다릅니다. 그래서 두 가지 실행 방법은 예외 처리하는 방식이 서로 다릅니다.

 

48.3. OS의 예외 처리 방법

48.3.1. 일반 실행의 경우 예외 처리 방법

프로세스가 실행할 때 예외가 발생하면 OS는 그 프로세스 자신이 예외를 처리하게 만듭니다. 포로세스 코드안에 SEH같은 예외 처리하는 코드가 있으면 예외를 잘 처리한 후 계속 진행할 수 있습니다. 그런데 SEH가 없으면 OS는 기본 예외 처리기를 동작시키고 프로세스를 종료시킵니다.

49.3.2. 디버깅 실행의 경우 예외 처리 방법

디버깅 중에 예외가 발생하면 OS는 먼저 디버거에게 처리를 맡깁니다. 그리고 디버거 실행이 중지되고 다른 방법을 취해야 디버깅을 계속할 수 있습니다. 아래는 자주 쓰는 몇 가지 방법입니다.

1) 예외 직접 수정: 코드, 레지스터, 메모리

이 경우에는 디버거를 통해서 문제가 발생한 코드, 메모리, 레지스터 등을 직접 수정하고 정상적인 진행할 수 있습니다.

2)예외를 디버기에게 넘겨서 처리

디버기 내부에 예외를 처리할 수 있는 SEH가 있으면 예외 통지를 디버기에게 보내서 자체 해결하게 만듭니다. 이와 일반 실행의 경우 똑같습니다.

3)OS 기본 예외 처리기

디버거와 디버기는 발생한 예외를 처리할 수 없으면 OS의 기본 처리기에서 처리하고 디버깅이 중지됩니다.

48.4. 예외

그 중에 대표적인 예외 다섯 가지가 있습니다.

1) EXCEPTION_ACCESS_VIOLATION(C0000005)

존재하지 않거나 접근 권한이 없는 메모리 영역에 접근할 때 발생하는 예외입니다.

2) EXCEPTION_BREAKPOINT(80000003)

실행 코드에 break point가 설치한 후 CPU가 그 주소를 실행하려 할 때 이 예외가 발생합니다.

3) EXCEPTION_ILLEGAL_INSTRUCTION(C000001D)

CPU가 해석할 수 없는 Instruction을 만날 때 발생하는 예외입니다.

4) EXCEPTION_INT_DIVIDE_BY_ZERO

정수 나눗셈 연산에서 분모가 0이면 이 예외가 발생할 것입니다.

5) EXCEPTION_SINGLE_STEP(80000004)

Flag 레지스터의 TF 비드를 1로 세팅하면 CPU Single Step 모드로 변경할 것입니다. CPU가 이 모드에서 명령어 하나를 샐행 후 이 예외를 발생시켜서 실행을 멈춥니다.

48.5. SEH 상세 설명

48.5.1. SEH체인

SEH는 체인 형태로 구성되어 있습니다. 첫 번쩨 예외 처리기에서 예외를 처리하지 못하면 다음 예외 처리기로 예외를 넘거줍니다.

아래의 코드는 SEH로 구성된 구조체입니다.

Next 멤버는 다음 구조체 포인터입니다.

Handler 멤버가 예외 처리기 함수입니다.

48.5.2. 함수 정의

아래의 코드는 예외 처리기 함수 정의입니다.

4개의 파라미터를 받으며 EXCEPTION_DISPOSITION이라는 열거형을 리턴합니다.

1)    EXCEPTION_RECORD

아래의 코드는 처리기 함수의 첫 번째 파라미터인 EXCEPTION_RECORD 구조체 정의입니다.

ExceptionCode 멤버는 발생한 예외의 종류를 의미합니다.

ExceptionAdress 멤버는 예외가 발생한 코드 주소를 나타냅니다.

1)    CONTEXT

아래의 코드는 처리기 함수의CONTEXT 구조체 정의입니다.

CONTEXT 구조체는 CPU레지스터 값을 백업할 때 사용합니다. CPU가 다른 스레드를 실행하려면 레지스터들의 값을 현재 스레드의 CONTEXT 구조체에 백업해야 합니다. 그 후에 CPU가 다시 예전의 스레드를 실행할 때 CONTEXT구조체에 백업된 레지스터 값을 실제 CPU 레지스터에 덮어씁니다.

48.5.3. SEH설치 방버

C언어에서 __try, __except, __finally  키워드로 구현할 수 있습니다.

어셈블리 언어에서는 아래의 코드로 추가할 수 있습니다.









'리버싱핵심원리' 카테고리의 다른 글

Reverse Engineering Chap 49  (0) 2016.02.11
Reverse Engineering Chap 47  (0) 2016.02.03
Reverse Engineering Chap 46  (0) 2016.02.03
Reverse Engineering Chap 50-51  (0) 2016.02.03
Reverse Engineering Chap 21-22  (0) 2016.02.03
Posted by 알 수 없는 사용자
2016. 2. 3. 17:03

chap 47. PEB


47.1. PEB


<PEB 접근 방법>

TEB에 있는 멤버 중 TEB.ProcessEnvironmentBlock 은 PEB 구조체의 주소를 나타낸다. ProcessEnvironmentBlock 은 TEB 구조체 시작으로부터 30오프셋 만큼 떨어져 있다. TED 구조체는 FS 세그먼트 셀렉터가 가리키고 있다. 따라서 다음과 같이 표현할 수 있다.

위의 공식을 어셈블리어로 표현하면 다음 두가지 방법으로 나타낼 수 있다. (두가지 방법 모두 TEB.ProcessEnvironmentBlock 멤버를 참조하고 있음)




47.2. PEB 중요 멤버 설명

PEB의 내용은 OS에 따라서 달라지고 멤버가 많기 때문에 리버싱에 있어서 중요한 멤버들만 살펴본다.


<PEB.BeingDebugged>

Kernel32!IsDebuggerPeresent()라는 API가 있다. 이 API는 현재 프로세스가 디버깅을 당하는지를 판단하여 0 또는 1을 리턴하는 함수이다. 이 함수가 참조하는 PEB의 멤버가 바로 PEB.BeingDebugged이다. (IsDebuggerPresent()는 Windows7에서는 Kernelbase.dll에 구현되어 있고, Windows XP 이하에서는 Kernel32.dll에 구현되어 있음) 이 값은 주로 리버싱 분야에서 안티 디버깅에 쓰인다. 예를 들어 이 값을 조사하여 디버깅중이라고 판단되면 프로세스를 종료시킨다.

Kernel32!IsDebuggerPresent()함수를 Ollydbg로 살펴보면 다음과 같다.

위의 두 줄을 통해 PEB의 주소를 얻고 세번째 줄에서는 +002 만큼 이동하여 PEB.BeingDebugged 멤버를 참조하는 것을 알 수 있다.

실제로 notepad.exe를 실행시켜서 첫 줄을 "MOV EAX,DWORD PTR FS:][30]"으로 바꾼 뒤 한 줄 실행시키면 EAX에 PEB 주소가 들어오며, hex dump에서 PEB를 살펴보면 +002 위치(PEB.BeingDebugged 멤버)에 1이 들어있는 것을 확인할 수 있다.


<PEB.ImageBaseAddress>

* ImageBase : PE파일이 메모리에 로딩되는 시작 주소

* GetModuleHandle() API : 모듈의 이름을 인자로 받아서 해당 모듈의 handle을 리턴하는 함수

Kernel32!GetModuleHandleA() API 내부를 살펴보면 다음과 같다.

PEB를 찾은 뒤 +008에 있는 ImageBase 멤버를 참조하는 것을 알 수 있다.


<PEB.Ldr>

PEB.Ldr 멤버는 _PEB_LDR_DATA 구조체의 포인터이다.

PEB.Ldr을 통해 프로세스에 로딩된 모듈(DLL)의 로딩 베이직 주소를 직접 구할 수 있다.

_PEB_LDR_DATA 구조체는 다음과 같다.

이 구조체에서 InLoadOrderMoudleList, InMemoryOrderModuleList, InInitializationOrderModuleList 세개의 멤버는 _LIST_ENTRY 구조체 타입이다. _LIST_ENTRY 구조체는 프로세스에 로딩된 DLL모듈마다 각각 생성성되며 양방향 연결 리스트로 연결된다. 즉, _PEB_LDR_DATA 구조체에서 알 수 있듯이 모듈들의 연결 방식을 세가지 지원한다.

_LIST_ENTRY 구조체는 다음과 같다.

_LIST_ENTRY 를 통해서 연결 리스트를 제공하고, 저장되는 정보는 _LDR_DATA_TABLE_ENTRY 구조체이다.


<PEB.ProcessHeap & PEB.NtGlobalFlag>

PEB.ProcessHeap 과 PEB.NtGlobalFlag 는 안티 디버깅에서 주로 쓰인다.

PEB.ProcessHeap은 HEAP 구조체를 가리키는 포인터이다.

HEAP 구조체는 다음과 같다.

이 중 Flags와 ForceFlags는 디버깅 중 특정한 값으로 세팅된다.

PEB.NtGlobalFlag는 0x70으로 세팅된다. (윈도우 XP 에서만 효과가 있는 기법이며, 실행중인 프로세스를 attach시킨 경우에도 이 특성이 나타나지 않음)

'리버싱핵심원리' 카테고리의 다른 글

Reverse Engineering Chap 49  (0) 2016.02.11
Reverse Engineering Chap 48  (0) 2016.02.03
Reverse Engineering Chap 46  (0) 2016.02.03
Reverse Engineering Chap 50-51  (0) 2016.02.03
Reverse Engineering Chap 21-22  (0) 2016.02.03
Posted by 알 수 없는 사용자
2016. 2. 3. 14:38

Chapter 46 TEB


 TEB는 프로세스에서 실행되는 스레드에 대한 정보를 담고 있는 구조체이다. 스레드별로 TEB 구조체가 하나씩 할당된다. 또한 TEB 구조체는 OS 종류별로 그 모양이 조금씩 달라지며 세부적인 내용에 대해서는 문서화 되어있다.


다음은 TEB 구조체의 정의이다.





위는 각각 Windows XP SP3, Windows 7의 TEB 구조체이다. 구성을 보면 Windows 7 이 XP보다 구조체가 더 커진 것을 확인 할 수 있다.


위의 많은 멤버중 유저 모드 디버깅에 중요한 멤버들은 다음과 같다.


먼저 TEB 구조체의 첫번째 멤버는  _NT_TIB 구조체이다. _NT_TIB 구조체의 정의는 다음과 같다. TIB는 Thread Information Block의 줄임말이다.


가장 첫번째 멤버인 ExceptionList 멤버는 _EXCEPTION_REGISTRATION_RECORD 구조체의 연결리스트를 가리키고 있다. 이것은 SEH(Structed Exception Handler)라고 하는 Windows OS의 예외 처리 메커니즘에 사용된다.(48장 참고) Self 멤버는 _NT_TIB 구조체의 셀프포인터이다. _NT_TIB 구조체는 TEB 구조체의 첫번째 멤버이기 때문에 이는 TEB 구조체의 포인터이기도 하다.


이제 TEB 구조체에 유저모드에서 접근하는 방법에 대해서 알아볼 것이다.

Ntdll.NtCurrentTeb() API는 현재 스레드의 TEB 구조체 주소를 리턴하는 함수이다. 이 함수가 어떻게 구현 되어 있는지 OllyDbg를 통해서 확인해보면, 해당 API의 코드는 다음과 같다.

MOV EAX,DWORD PTR FS:[18]

RETN

 매우 간단한 코드로, 단순이 FS:[18] 주소의 값을 리턴하는 것이다. 그렇다면 이제 FS 세그먼트 레지스터에 대해서 알아볼것이다.


FS 세그먼트 레지스터는 현재 스레드의 TEB를 지시하는데 사용된다. IA32 시스템에서 프로세스의 가상 메모리 크기는 4GB이므로 32비트 크기의 포인터를 이용해야 전체 메모리 공간이 접근이 가능하다. 그러나 FS 레지스터의 크기는 16바이트이다. FS 세그먼트 레지스터는 TEB를 지시하는데 사용되지만, 직접 TEB 주소를 가리키는 것이 아니라 실제 TEB 주소를 갖고 있는 Segment Descriptor Table의 Index 값을 갖고 있는 것이다.


GDTR 레지스터에 Segment Descriptor Table의 시작 주소가 저장 되어있고 FS 레지스터에 그 인덱스가 저장 되어있다. 


따라서 FS:[0x18]은 Segment Descriptor Table에서 0x18 인덱스에 있는 주소 값에 있는 값을 의미한다. 이는 TEB에서 _NT_TIB 구조체 내의 Self 멤버를 의미하며 이는 _NT_TIB 구조체의 주소이자 TEB 구조체의 주소를 의미한다. 허나 0x18 인덱스의 Self 멤버의 값에 접근하지 않고 바로 FS:0 으로 접근하여 TEB의 주소를 구할 수도 있다.


하여 마지막으로 FS 레지스터 인덱스의 중요한 멤버들은 다음과 같다.

FS:[0x30] = TEB.ProcessEnvironmentBlock = PEB 시작 주소

 FS:[0x30]은 TEB 구조체 내의 ProcessEnvironmentBlock 멤버의 값을 의미하는데 이는 PEB의 주소를 의미한다. PEB에 대해서는 다음 챕터에서 다룰 예정이다.


FS:[0] = TEB.NtTib.ExceptionList = SEH 시작 주소

 위에서 언급하였듯이 FS:[0]은 _NT_TIB 구조체의 첫번째 멤버인 ExceptionList를 의미한다. 이는 SEH의 시작 주소를 의미한다. SEH는 48 챕터에서 다룰 예정이다.






'리버싱핵심원리' 카테고리의 다른 글

Reverse Engineering Chap 48  (0) 2016.02.03
Reverse Engineering Chap 47  (0) 2016.02.03
Reverse Engineering Chap 50-51  (0) 2016.02.03
Reverse Engineering Chap 21-22  (0) 2016.02.03
Reverse Engineering Chap 45  (0) 2016.01.30
Posted by 키흐
2016. 2. 3. 09:31

50. 안티 디버깅

디버깅 -> 프로그램의 코드 흐름과 데이터 구조를 쉽게 파악 가능
안티 디버깅을 통해 이를 방지

안티 안티 디버깅 : 리버서들이 안티 디버깅을 상대하는 방법을 일컫는다.




static

디버깅을 시작할 때 한번만 해체해주면 되는 기법
이 기법이 적용된 파일은 RUN조차 되지 않음.
static 기법을 해제해줘야 실행 가능

dynamic

만날 때마다 해결해줘야함.
RUN은 되지만 TRACING은 방해하여 원본 프로그램의 코드와 데이터를 확인할 수 없게 만든다.

run : 디버기 프로세스를 실행시키는 것
trace : 디버기의 내부 Instruction 을 하나씩 실행하면서 레지스터, 메모리(스택) 등을 실시간으로 확인하는 것


51. Static Anti Debugging

51.1. 목적

디버깅중이라고 판단되면 일반 실행과는 다른 코드를 실행
구현 방법 : 디버거 탐지 / 디버깅 환경 탐지 / 디버거 강제 분리
회피 방법 : 탐지 코드에서 얻어오는 정보를 파악하여 그 정보 자체를 변경

51.2. PEB

Process Environment Block : 프로세스 환경 정보가 담겨져 있다.
신용 가능하고, 사용또한 쉽기 대문에 가장 널리 사용되는 안티 디버깅 기법

Windows XP SP3의 PEB 구조체에서 안티 디버깅을 위해 사용되는 멤버는 아래와 같다

+0x002 BeingDebugged    : UChar
+0x00c Ldr              : Ptr32_PEB_LDR_DATA    
+0x018 ProcessHeap      : Ptr32_Void
+0x068 NtGlobalFlag     : Uint4B 

PEB 구하는법 : 올리디버거로 해당 디버기 불러왔을 때, EBX에 저장된 값이 PEB의 시작주소

51.2.1. BeingDebugged (+0x2)

디버깅 중이면 1, 일반 실행이면 0

IsDebuggerPresent()를 통해 이 값을 가져오고, 이로써 디버깅 여부를 판별한다.

회피방법 : 0으로 변경

51.2.2. Ldr (+0xC)

디버깅 프로세스는 힙 메모리 영역에 자신이 디버깅 당하는 프로세스라는 표시를 한다. 그 중 가장 큰 특징은 사용되지 않는 역역은 0xFEEEFEEE 로 채운다는 것이다. 이를 통해 디버깅 여부 판별 가능하다.

Ldr 주소로 가면 0xFEEEFEEE를 찾을 수 있다.

회피방법 : NULL로 덮어씌우면 된다.

XP 이하에서만 동작하고 Vista 이후부터는 동작하지 않는다.

51.2.3. Process Heap (+0x18)

heap 구조체를 가리키는 포인터이다.
heap 구조체 중 Flags(+0xC) 와 Force Flags(+0x10) 멤버는 디버깅 중 특정한 값으로 세팅된다.

일반 실행시 Flags는 0x2 이고, ForceFlags는 0x0 이다.
디버깅 중에는 이 값들이 변경된다.

회피방법 : 정상 값으로 변경.

XP에서만 효과가 있다.

51.2.4. NtGlobaIFlag (+0x68)

디버깅 중일때는 이 값이 0x70으로 세팅된다.

회피방법 : 0x0으로 세팅

51.3. NtQueryInformationProcess()

ntdll!NtQueryInformationProcess() API를 사용하여 프로세스의 정보를 가져온 후, 이 중 디버깅 관련 정보를 통해 안티 디버깅을 수행한다.

3번째 파라미터인 PVOID ProcessInformation에 해당 정보가 세팅되는데 이 정보 중, ProcessDebugPort(0x7), Process DebugObjectHandle(0x1E), ProcessDebugFlags(0x1F) 가 사용된다.




51.3.1. ProcessDebugPort(0x7)

프로세스가 디버깅 중일 때 Debug Port가 할당된다.

디버깅 중이 아니라면 0이 세팅되지만
디버깅중이라면 0xFFFFFFFF 가 세팅된다.

CheckRemoteDebuggerPresent()를 통해 이 값을 가져오고, 이로써 디버깅 여부를 판별한다.

51.3.2. ProcessDebugObjectHandle(0x1E)

프로세스가 디버깅될 때 Debug Object가 생성된다.

디버깅 중이라면 Handle 값이 존재하고, 디버깅중이 아니라면 Handle은 NULL이다.

51.3.3. ProcessDebugFlags(0x1F)

0이면 디버깅 상태이고, 1이면 디버깅이 아니다.

51.3.4. 회피방법

API 후킹을 통해 특정 파라미터일 때 무조건 정상 값을 반환하도록 조작함.

51.4. NtQuerySystemInformation()

디버깅 환경을 체크하는 안티 디버깅 기법
OS가 Debug Mode로 부팅되었는지를 판단하는 안티 디버깅 기법

ntdll!NtQuerySystemInformation() API 를 통해 현재 동작 중인 OS 시스템에 대한 다양한 정보를 구할 수 있다.

첫번째 파라미터인 SYSTEM_INFORMATION_CLASS SystemInformationClass 에 SystemKernelDebuggerlnformation(0x23) 을 입력하면 현재 OS 시스템이 디버그 모드로 부팅되었는지 알 수 있다.

디버그 모드인 경우 SYSTEM_KERNEL_DEBUGGER_INFORMATION.DebuggerEnabled는 1에 세팅된다.

[회피]
xp의 경우, boot.ini를 편집하고 ‘/debugport=com1 /bandrate=115200 /Debug’ 값을 제거한다.
7의 경우, cmd 창에서 ‘bcdedit /debug off’ 명령을 내리고 재부팅하면 일반모드로 부팅된다.

51.5. NtQueryObject()

프로세스가 디버깅될 때 Debug Object가 생성되는데 이 존재를 확인하는 방법이다.

ntdll!NtQueryObject()는 시스템의 다양한 종류의 커널 객체 정보를 구해오는 함수이다.

두번째 파라미터에 원하는 값을 입력하고 API를 호출하면 세번째 파라미터에 관련 정보의 구조체 포인터를 리턴한다.

ObjectAllTypesInformaion 항목을 이용하여 시스템의 모든 객체 정보를 구한 다음 그 중에 DebugObject가 있는지 확인한다.

회피방법 : 이 함수가 호출될 때 breakpoint를 걸어 두번째 파라미터에 3(ObjectAllTypesInformaion)이 아닌 0(ObjecBasicTypesInformaion)이 들어가게 한다.

51.6. ZwSetInformationThread()

디버기에서 강제로 디버거를 떼어내는 기법이다.
이 함수는 스레드에게 정보를 세팅하는 System Native API이다.

첫번째 파라미터에 현재 스레드의 핸들을 넘겨주고
두번째 파라미터에 ThreadHideFromDebugger(Ox11) 값을 입력하면 디버거 프로세스가 분리된다.

회피방법 : breakpoint 를 걸어 두번째 파라미터에 0x11이 들어가 있다면 0으로 변경한다.

51.7. TLS

45장 참고

51.8. ETC

  • 디버거 창 검색
  • 디버거 프로세스 검색
  • 컴퓨터 이름 확인 (TEST, ANALYSIS)
  • 프로그램 실행 경로 검사 (TEST, SAMPLE)
  • 가상 머신 실행 중인지 확인

회피방법 : 반환되는 문자열을 NULL로 세팅

'리버싱핵심원리' 카테고리의 다른 글

Reverse Engineering Chap 47  (0) 2016.02.03
Reverse Engineering Chap 46  (0) 2016.02.03
Reverse Engineering Chap 21-22  (0) 2016.02.03
Reverse Engineering Chap 45  (0) 2016.01.30
Reverse Engineering Chap 34  (0) 2016.01.27
Posted by 덜키
2016. 2. 3. 09:28

21. Windows Message Hooking

21.1. Hook

Hook(갈고리)는 원하는 것을 낚아채고 싶을 때 사용하는 도구이다. 컴퓨터 분야에서는 정보를 엿보거나 가로채는 경우에 사용되는 단어로 확장되어 사용된다. Hook을 하는 행위를 ‘후킹한다(Hooking)’라고 표현하는데 이는 중간에서 오고가는 정보를 엿보거나 가로채기 위한 일을 하거나 정보를 조작하는 행위를 의미한다. 실제로 ‘OS-Application-User’ 사이의 정보를 모두 조작 가능하다. 가장 기본적인 방식의 후킹은 Message Hook이다.


21.2. Message Hook

Windows 운영체제는 GUI를 제공하고, 이는 Event Driven1 방식으로 동작한다. 이벤트가 발생할 때 OS는 미리 정의된 메시지를 해당 응용프로그램으로 보낸다.

Created with Raphaël 2.1.2이벤트정의된 메시지응용프로그램

일반적인 경우의 Windows 메시지 흐름

Created with Raphaël 2.1.2키보드키보드OS message queueOS message queueApplication message queueApplication message queueWM_KEYDOWNmonitoringWM_KEYDOWNHook ChainEvent Handler 호출

Hook Chain의 키보드 메시지 훅들은 해당 메시지 열람 및 변조가 가능하다. Hook Chain은 동시에 여러개 설치가 가능하며, 설치 순서대로 호출된다. 이러한 특성때문에 Hook Chain이라고 불린다.


21.3. SetWindowsHookEx()

메시지 훅은 SetWindowsHookEx() 함수를 통해 간단히 구현할 수 있다.

//SetWindowsHookEx() API
HHOOK SetWindowsHookEx(
    int idHook,          // hook type
    HOOKPROC lpfn,       // hook procedure : 운영체제가 호출해주는 콜백함수
    HINSTANCE hMod ,     // 위 hook procedure가 속해있는 DLL 핸들
    DWORD dwThreadld     // Hook을 걸고 싶은 thread의 ID. 0을 주고 호출하면 글로벌 훅
);

21.4. 키보드 메시지 후킹 실습

enter image description here

  1. HookMain.exe는 KeyHook.dll을 최초로 로딩하여 키보드 훅을 설치하는 프로그램
  2. KeyHook.dll은 훅 프로시저가 존재하는 DLL 파일
  3. SetWindowssHookEx()를 이용하여 키보드 훅 설치
  4. 다른 프로세스에서 키 입력 이벤트가 발생하면 OS 에서 해당 프로세스의 메모리 공간에 KeyHook.dll을 강제로 로딩
  5. KeyboardProc() 함수가 호출됨

21.4.1. 실습 예제

21.4.2. 소스코드 분석

HookMain.cpp

#include "stdio.h"
#include "conio.h"
#include "windows.h"

#define DEF_DLL_NAME "KeyHook.dll"
#define DEF_HOOKSTART "HookStart"
#define DEF_HOOKSTOP "HookStop"

typedef void(*PFN_HOOKSTART)();
typedef void(*PFN_HOOKSTOP)();

void main()
{
    HMODULE hDll - NULL;
    PFN_HOOKSTART HookStart = NULL;
    PFN_HOOKSTOP HookStop = NULL;
    char ch = 0;

    // KeyHook.dll 로딩
    hDll = LoadLibraryA(DEF_DLL_NAME);

    //export 함수 주소 얻기
    HookStart =(PFN_HOOKSTART)GetProcAddress(hDll, DEF_HOOKSTART); 
    HookStop =(PFN_HOOKSTOP)GetProcAddress(hDll, DEF_HOOKSTOP);

    // 후킹 시작
    HookStart();

    // 사용자가 'q'를 입력할 때까지 대기
    printf("press 'q' to quit\n");
    while( _getch() != 'q' );

    // 후킹 종료
    HookStop();

    // KeyHook.dll 언로딩
    FreeLibrary(hDll);
}

KeyHook.cpp

#include "stdio.h"
#include "windows.h"

#define DEF_PROCESS_NAME "notepad.exe"

HINSTANCE g_hInstance = NULL;
HHOOK g_hHook = NULL;
HWND g_hWnd = NULL;

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpvReserved)
{
    switch(dwReason)
    {
        case DLL_PROCESS_ATTACH:
            g_hInstance = hinstDLL;
            break;

        case DLL_PROCESS_DETACH:
            break;
    }
    return TRUE;
}

LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    char szPath[MAX_PATH] = {0,};
    char *p = NULL;

    if(nCode = 0) 
    {
        // bit 31: 0 = key press, 1 = key release
        if( !(lParam & 0x80000000) )  // 키보드가 눌렀다 떨어질 때
        {  
            GetModuleFileNameA(NULL, szPath, MAX_PATH);
            p = strrchr(szPath, '\\');

            // 현재 프로세스 이름을 비교해서 만약 notepad.exe. 라면,
            // 메시지는 응용 프로그램(혹은 다음 훅)으로 전달되지 않음
            if( !_stricmp(p+1, DEP_PROCESS_NAME)
                return 1;
        }
    }

    // 일반적인 경우에는 CallNextHookEx()를 호출하여
    // 응용 프로그램(혹은 다음 훅)으로 메시지를 전달함
    return CallNextHookEx(g_hHook, nCode, wParam, lParam);
}

#ifdef __cplusplus
extern "C" {
#endif
__declspec(dllexport) void HookStart() 
{
    g_hHook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, g_hInstance, 0);
}
__declspec(dllexport) void HookStop() 
{
    if(g_hHook) 
    {
        UnhookWindowsHookEx(g_hHook);
        g_hHook = NULL;
    }
}
#ifdef __cplusplus
}
#endif

21.5. Debugging

21.5.1. ‘HookMain.exe’ 디버깅

  • “press ‘q’ to quit!” 문자열을 참조한 코드를 찾음 으로써 main 함수 찾는다.
  • main 함수에 breakpoint를 걸어 HookStart()가 실행될 때 까지 디버깅
  • HookStart() 해당 주소의 CALL EAX 를 따라가서 KeyHook.dll의 함수임을 확인
  • HookStart에서 사용되는 SetWindowsHookExW() 함수 및 파라미터 확인

21.5.2. Notepad.exe 프로세스 내의 KeyHook.dll 디버깅

  • OllyDbg의 옵션(‘Break on new module(DLL)’을 Check 상태로 변경함으로써 새로운 DLL이 로딩될 때마다 자동으로 디버깅을 멈출 수 있다.
  • 이 상태에서 HookMain.exe를 실행하고 notepad.exe 에서 키보드를 입력하면 OllyDbg가 멈추면서 ‘Executable modules’ 창이 뜬다.
  • 여기서 KeyHook.dll이 로딩된 것을 확인할 수 있다.

22. 악의적인 목적으로 사용되는 키로거

관리 차원에서 (사용자 동의하에) 사용되는 키로거는 나쁘다고 할 수 없을 것이다. 하지만 악의적인 목적으로 사용자 몰래 실행되는 키로거는 문제가 된다.

22.1. 악성 키로거의 목표 및 사례

  • 목표 : 돈
  • 사례
    • 온라인 게임
    • 인터넷 뱅킹
    • 기업 정보 유출

22.2. 키로거의 종류와 향후 발전 방향

키보드 끝에 연결되어 키보드의 입력이 PC로 전달되는 과정에서 가로챈다. 내부에 flash memory를 내장하고 있어 키보드로부터 들어오는 전기 신호를 직접 입력받아 저장하는 장치이다.

22.3. 키로거에 대처하는 우리의 자세

  • 공공장소에서는 개인정보 입력 X
  • 보안 프로그램 업데이트
  • 개인정보 복붙으로 입력
  • 개인 방화벽 사용

22.4. 개인정보

비밀번호 어렵게 하자


  1. 이벤트에 반응하여 동작을 변경하는 방식

'리버싱핵심원리' 카테고리의 다른 글

Reverse Engineering Chap 46  (0) 2016.02.03
Reverse Engineering Chap 50-51  (0) 2016.02.03
Reverse Engineering Chap 45  (0) 2016.01.30
Reverse Engineering Chap 34  (0) 2016.01.27
Reverse Engineering Chap 3-6  (0) 2016.01.27
Posted by 덜키
2016. 2. 1. 02:21

Crackit2.exe 의 flag 를 찾는 것이 목표이다.

기본적으로 프로그램을 실행시켜서 아무 값이나 입력하면 다음과 같다.

Ollydbg를 이용하여 이 프로그램을 열고 "All referenced text string" 창을 열면 다음과 같이 "ACCESS DENIED" 와 "ACCESS GRANTED" 를 찾을 수 있다.

"ACCESS GRANTED" 와 ACCESS DENIED" 분기문으로 갈리는 지점을 찾아가면 다음과 같다.

004027A7 에서 EAX 값을 테스트하여 바로 JNZ 를 통해 분기하는 것을 알 수 있다.

004027A7을 실행하기 직전의 레지스터 값을 보면 다음과 같다.

EAX에 FFFFFFFF가 들어있는데, 위의 분기문에서 "ACCESS DENIED"가 있는 부분으로 점프하지 않고 "ACCESS GRANTED"가 있는 부분으로 넘어가기 위해서는 EAX의 값이 0이 되어야 함을 알 수 있다.


이제 다시 프로그램을 처음부터 실행시켜 보자.

빈칸에 아무 값이나 입력하고 코드 부분을 보면 다음과 같은 내용이 나온다.

004022E4에서 PUSH EAX 을 실행하는데, EAX에는 내가 입력한 값이 들어있었다. 따라서 EAX 값을 스택에 저장한 뒤 MSVBVM60.__vbaLenBstr 함수를 호출하여 입력한 값의 길이를 구하게 된다. 그 값은 다시 EAX에 저장되게 된다. 그 후 004022ED에서 CMP EAX,7 을 실행하는데, 이는 그 길이가 7인지 확인하는 부분이다.

그 밑으로 몇줄 내려오면 다음과 같다.

0040230C 에서 JE 명령어가 나오는데, 이는 CMP EAX,7에서 EAX가 7이 아닐 경우 zero flag가 1이 되기 때문에 점프를 실행하게 된다. EAX가 7이면 바로 다음 줄의 명령을 실행하게 된다.

일단 7이 아닌 크기의 문자열을 입력하여 점프를 실행하면 이 글의 첫 부분에서 말했던 분기점 부분으로 바로 넘어가게 된다.

0040279D에서 "yes"라는 값을 스택에 넣고 vbaStrCmp 함수를 호출한다. 그런데, vbaStrCmp는 스택에 있는 두 개의 값을 불러들여 비교하게 되는데, "yes"가 하나 들어있기 때문에 비교하면 EAX에 FFFFFFFF라는 값이 결과값으로 들어가게 된다. 따라서 바로 "ACCESS DENIED" 부분으로 넘어가게 된다. 즉, 이제 나는 7글자의 문자열을 입력한 뒤 그 문자열을 분석하는 코드를 지나면서 스택에 "yes"가 들어갈 수 있게 하면 된다.

이제 문자열 7개를 분석하는 부분에 초점을 맞춘다. 그 중 어떠한 값을 스택에 넣고 vbaStrCmp를 호출한 뒤 점프를 실행하는 부분을 발견할 수 있다.

그 중 최초로 값을 비교하는 부분에서 스택을 확인하면 내가 입력했던 값이 한 글자씩 차례대로 스택에 저장되어 있음을 확인할 수 있다.

즉, 내가 입력했던 글자 하나하나를 비교하여 틀리면 바로 점프를 통해 넘어가는 코드 내용임을 알 수 있다. 따라서 코드에 나와있는 유니코드에 해당하는 글자 7개가 flag임을 알 수 있다. 그런데 flag에서 4번째와 6번째 문자는 char 형으로 저장되고, 나머지는 유니코드로 저장된다. 따라서 비교할 때도 그렇게 비교하게 되는데, 위에 코드에서 유니코드 부분과 char 부분을 구분할 필요가 있다. 따라서 유니코드를 char로 변환하면 flag가 최종적으로 "Ech3l0n" 임을 알 수 있다.


'WriteUp' 카테고리의 다른 글

Crackit2.exe Writeup  (0) 2016.01.15
Crackit2.exe Writeup  (0) 2016.01.14
[예시] Easy Keygen (100pt)  (0) 2016.01.11
Posted by 알 수 없는 사용자
2016. 1. 30. 21:27

TLS 콜백은 프로세스에서 스레드가 생성되기 전, 스레드가 종료된 후 자동으로 실행되는 함수 들이다 . 메인 함수가 실행되는 스레드도 예외가 아니기 때문에 메인함수 시작 전에도 TLS 콜백이 실행된다. 메인의 엔트리 포인트 이전에 실행되기 때문에 안티 디버깅을 위한 용도로 쓰이기도 한다.


TLS TLS 콜백을 등록하기 위해서는 아래와 같은 형태의 함수를 사용해야한다.이 형태는 DLL에서 쓰이는 것과 같다.


예제 코드


#pragma comment(linker, "/INCLUDE:__tls_used")

#pragma data_seg(".CRT$XLX")

PIMAGE_TLS_CALLBACK TLS_CALLBACk[] = { tlsCallback, 0 };

#pragma data_seg()


위의 코드가 TLS를 사용하기 위해 필요하다. .CRT$XLX 영역에 PIMAGE_TLS_CALLBACK 변수 또는 배열을 이용하여 TLS 콜백 함수들을 등록한다.

위의 코드를 실행하면 아래와 같은 결과를 볼 수 있다.

메인 함수가 실행되기 전 TLS 콜백이 실행되어 문자열 TLS가 출력된다.

스레드 실행 전 후로 TLS 콜백이 실행되는 것을 확인할 수 있다.

디버깅을 해보면 메인 함수 종료 후에도 TLS 콜백이 실행되나 printf 함수가 제대로 동작하지 않아 실제로 출력은 되지 않는다.


PE 내부 TLS의 위치와 구조

TLS를 사용하면 IMAGE_NT_HEADER.IMAGE_OPTIONAL_HEADER.IMAGE_DATA_DIRECTORY[9]에 TLS 테이블의 크기와 RVA가 기록된다.


PEview로 확인하면 TLS table에 대한 정보가 있는 것을 확인할 수 있다.

RVA 0x176EC에 해당하는 RAW인 0x68EC에는 IMAGE_TLS_DIRECTORY가 있다.


IMAGE_TLS_DIRECTORY 구조체 중 Address of Callbacks에 TLS 콜백 함수들의 주소(VA)가 저장되어있다.

00416720에 해당하는 곳은 아래 그림에서 볼 수 있다.


Address of Callbacks에 해당하는 곳인 0x00416720의 모습이다. 콜백 함수들의 주소가 저장되고 마지막은 NULL로 끝난다. 우리가 정의한 함수의 주소인 0x004110EB는 아래의 그림에 있다.


0x004110EB의 값을 보면 E9로 시작한다. E9 XXXXXXXX는 점프문에 해당하기 때문에 점프 주소를 쉽게 확인하기 위해 올리 디버거로 확인해보았다.


올리 디버거로 확인해보면 VA 0x004110EB에는 JMP 007316E0 명령어가 있고, 이 점프문을 따라가면 우리가 정의했던 TLS 콜백 함수가 나타난다.


문자열 TLS를 스택에 넣고 출력하는 것으로 보아 우리가 정의했던 TLS 콜백 함수임을 알 수 있다.

'리버싱핵심원리' 카테고리의 다른 글

Reverse Engineering Chap 50-51  (0) 2016.02.03
Reverse Engineering Chap 21-22  (0) 2016.02.03
Reverse Engineering Chap 34  (0) 2016.01.27
Reverse Engineering Chap 3-6  (0) 2016.01.27
Reverse Engineering Chap 33  (0) 2016.01.27
Posted by 지환태
2016. 1. 27. 23:54

Chap 34. 고급 글로벌 API 후킹 - IE 접속 제어


이번 장의 실습 목표는 IE 프로세스의 API를 후킹하여 특정 사이트로 향하는 접속을 다른 사이트로 우회시키는 것이다.


34.1. IE 프로세스 구조


- IE 7부터는 탭 개념을 도입하면서 프로세스 구조가 부모-자식 관계임


34.2. 글로벌 API 후킹 개념 정리


- 일반적인 API 후킹은 Test.exe 프로세스에 인젝션하여 후킹하는 방법 --> 후킹 대상 프로세스가 새로 생성될 때마다 수동으로 API 후킹을 해야 함

- 글로벌 API 후킹은 Windows OS의 기본 Shell인 Explorer.exe 프로세스에 인젝션하여 자식 프로세스 생성에 관련된 API를 후킹하여 자식 프로세스를 생성할 때마다 인젝션 하도록 하는 것임


34.3. ntdll!ZwResumeThread() API

- 글로벌 API 후킹을 하기 위해서는 자식 프로세스를 생성하는 API에 대해 알아야 함

- 프로세스를 생성하는 대표적인 API는 Kernel32!CreateProcess() 임

- CreateProcessW() API의 호출 흐름은 다음과 같음

- 위의 4개의 API 중 어떤 것을 후킹해도 글로벌 API 후킹이 가능하지만 이번 실습에서는 ntdll!ZwResumeThread() API 를 후킹함


34.4. redirect.cpp

- DllMain() 함수에서는 ntdll!ZwResumeThread() 와 wininet!InternetConnectW() API 를 훅/언훅 하는 기능을 함

- NewInternetConnectW() 함수에서는 IE 의 접속 주소를 모니터링 하면서 특정 사이트에 접속할 때 원하는 사이트로 접속을 돌리는 역할을 함

- NewZwResumeThread() 함수에서는 자식 프로세스에 redirect.dll을 인젝션해주는 역할을 함

redirect.cpp


34.5. 실습 예제 - IE 접속 제어


InjDll32.exe

InjDll64.exe

redirect.dll

- InjDll.exe 프로그램은 책 저자가 만든 프로그램(target 프로세스가 32bit인지 64bit인지에 따라 선택해서 사용하면 됨) --> 타깃 프로세스에 원하는 DLL을 인젝션/이젝션하는 기능을 함









'리버싱핵심원리' 카테고리의 다른 글

Reverse Engineering Chap 21-22  (0) 2016.02.03
Reverse Engineering Chap 45  (0) 2016.01.30
Reverse Engineering Chap 3-6  (0) 2016.01.27
Reverse Engineering Chap 33  (0) 2016.01.27
Reverse Engineering Chap 32  (0) 2016.01.24
Posted by 알 수 없는 사용자
2016. 1. 27. 15:52

Chapter 3 리틀 엔디언 표기법

3.1 바이트 오더링

- 컴퓨터 메모리에 저장하는 순서입니다

-빅 엔디언과 리틀 엔디언

아래 코드는 4가지 자료형이 있습니다. 다른 엔디언 방식에 따라서 같은 데이터는 저장되는 방식이 다릅니다.

       

바이트 타입의 변수를 저장할 때는 두 방식의 차이가 없습니다. 하지만 2바이트 이상의 크기를 가진 자료형을 저장할 때부터 차이가 나타납니다. 빅 엔디언 방식은 정상적인 순서로 데이터를 저장하고 리틀 엔디언 방식은 역순으로 데이터를 저장합니다. 또한 문자열은 저장 방식에 상관없이 동일합니다.


예제 소스


이 코드를 빌드하고 생성한 파일을 디버깅합니다.

Main()함수의 주소는 401000입니다. 변수들의 주소는 40AC40, 40AC44, 40AC48, 40AC4C입니다. 


데이터 창을 통해 이 메모리 영역으로 갑니다. 변수 w와 dw의 값이 리틀 엔디언 형식으로 저장된 것을 알 수 있습니다.


Chapter 4 IA_32 Register 기본 설명

4.1 IA-32의 Register

아래의 그림은 Basic program execution registers에 대해 나와 있습니다. 4가지의 그룹으로 나눌 수 있습니다.

- General Purpose Registers (32 비트 - 8개)

- Segment Registers (16 비트 - 6개)

- program Status and Control Register (32 비트 - 1개 )

- Instruction Pointer (32비트 - 1개)


4.1.1 General Purpose Registers(범용 레지스터)

General Purpose Registers는 범용적으로 사용되는 레지스터입니다. 데이터를 전송하고 임시 보존할  수 있습니다. 그리고 산술 연산을 할 수 있고 그 연산한 결과를 저장할 수 있습니다. IA-32에서 각각의 범용 레지스터의 크기는 32비트이고 주로 상수와 주소 등을 저장합니다.

위 4개의 레지스터는 주로 산술연산을 하는 것이고 상수와 변수 값을 저장할 때 사용됩니다. 그리고 ECX와 EAX는 특수한 용도가 있습니다. ECX는 반복문 병령어(loop)에서 반복 카운트(loop count)로 사용됩니다. EAX는 일반적으로 함수 리턴 값에 사용됩니다.


위 4개의 레지스터는 주로 메모리 주소를 저장하는 포인터로 사용됩니다. EPS는 스택 메모리 주소를 가리키고 EBP는 함수가 호출되었을 때의 ESP를 저장하고 함수가 리턴하기 전에 다시 ESP에 값을 되돌려 줍니다. 그리고 ESP와 EDI는 어떤 특정어들(LODS, STOS, REP MOVS 등)과 함께 사용되고 주로 메모리 복사에 사용됩니다.


4.1.2 Segment Register

IA-32 보호 모드에서 세그먼트는 메모리를 조각내서 각 조각마다 시작 주소, 범위, 접근 권한 등을 부여해서 메모리를 보호하는 기법입니다.

- CS는 프로그램의 코드 세그먼트를 나타냅니다.
- SS는 스택 세그먼트를 나타냅니다, 
- DS는 데이터 세그먼트를 나타냅다. 
- ES, FS, GS는 추가적인 데이터 세그먼트를 나타냅니다. 

4.1.3 Program Status and Control Register(프로그램 상태와 컨트롤 레지스터)

이flag 레지스터는 32개의 비트가 있는데 각 비트를 전부 이해하는 것은 어려워서 먼저 애플리케이션 다버깅에 필요한 3가지flag에 대해서 잘 이해하면 됩니다.

- Zero Flag(ZF): 연산 명령 후에 결과 값이 0이 되면 ZF가 true로 세팅됩니디.

- Overflow Flag(OF): 부호 있는 수의 오버플로가 발생했을 때 true로 세팅됩니다. 그리고 MSB(Most significant Bit)가 변경되었을 때 true로 세팅됩니다. 

- Carry Flag(CF): 부호 없는 수의 오버플로가 발생했을 때 true로 세팅됩니다.


4.1.4 Instruction Pointer(EIP)

EIP CPU가 처리할 명령어의 주소를 나타내는 레지스터입니다. CPU EPI에 저장된 메모리 주소의 명영어를 하나 처리하고 난 후 자동으로 그 명령어 길이만큼 EIP를 증가시킵니다.

 

4.1.4 Instruction Pointer(EIP)

EIP CPU가 처리할 명령어의 주소를 나타내는 레지스터입니다. CPU EPI에 저장된 메모리 주소의 명영어를 하나 처리하고 난 후 자동으로 그 명령어 길이만큼 EIP를 증가시킵니다.

 

Chapter 5 스택

5.1. 스택

스택은 다양한 용도가 있는데 주로 함수 내의 로컬 변수를 임시 저장하고 함수 호출 시 파라미터를 전달하고 복귀 주소를 저장할 때 자주 사용합니다. 그리고 스택은First in Last Out 구조가 있습니다. 프로세스에서 스택 포인터는 처음에 제일 아래에 있습니다. Push 명령을 통해서 Stack에 값이 추가되면 스택 포인터는 위에 움직입니다. 그리고 pop명령을 통해서 값이 제거되면 스택 포인트는 아래에 움직입니다.

5.2 스택 동작예제

아래의 그림은 스택 초기 상태이며 스택 포인터(ESP)의 값은 12FF8C입니다.


PUSH명령을 실행한 후 ESP의 값은 12FF88로 바구고 4바이트 줄어들었습니다.


POP명령을 실행한 후 ESP의 값은 다시 12FF88로 바구고 4바이트 증가했습니다.


이 예제를 통해 스택 포인터의 변화를 더 잘 이해할 수 있습니다.


Chapter 6 abex’ crackme #1 분석

먼저 파일을 실행합니다.


[확인]을 눌러서 ‘Error’ 메시지 박스가 나온다


이 파일을 디버깅하고 이런 코드를 볼 있습니다. 


401026주소의 JE 명령어를 JMP명령어로 부꾸면 됩니다.


[확인]을 누르면 성공 메시지 박스 나올 수 있습니다.



.








'리버싱핵심원리' 카테고리의 다른 글

Reverse Engineering Chap 45  (0) 2016.01.30
Reverse Engineering Chap 34  (0) 2016.01.27
Reverse Engineering Chap 33  (0) 2016.01.27
Reverse Engineering Chap 32  (0) 2016.01.24
Reverse Engineering Chap 28  (0) 2016.01.24
Posted by 알 수 없는 사용자