<4D6963726F736F667420576F7264202D20C0A9B5B5BFECBDC3BDBAC5DB5FBBF9C7C3B1B3C0E75FC7A5C1F6>



Similar documents
Deok9_Exploit Technique

hlogin2

K&R2 Reference Manual 번역본

Deok9_PE Structure

6주차.key


IDA 5.x Manual hwp

No Slide Title

INTRO Basic architecture of modern computers Basic and most used assembly instructions on x86 Installing an assembly compiler and RE tools Practice co


프로그램을 학교 등지에서 조금이라도 배운 사람들을 위한 프로그래밍 노트 입니다. 저 역시 그 사람들 중 하나 입니다. 중고등학교 시절 학교 도서관, 새로 생긴 시립 도서관 등을 다니며 책을 보 고 정리하며 어느정도 독학으르 공부하긴 했지만, 자주 안하다 보면 금방 잊어

10주차.key

강의10

hlogin7

5.스택(강의자료).key

슬라이드 1

1장 윈도우 프로그래밍 들어가기

초보자를 위한 C# 21일 완성

The_IDA_Pro_Book

Microsoft PowerPoint - a10.ppt [호환 모드]

PCServerMgmt7

(Asynchronous Mode) ( 1, 5~8, 1~2) & (Parity) 1 ; * S erial Port (BIOS INT 14H) - 1 -

13주-14주proc.PDF

Microsoft PowerPoint - a8a.ppt [호환 모드]

untitled

02 C h a p t e r Java

thesis

<C0CCBCBCBFB52DC1A4B4EBBFF82DBCAEBBE7B3EDB9AE2D D382E687770>

03장.스택.key

1217 WebTrafMon II

Chap06(Interprocess Communication).PDF

untitled

<B1E2BCFAB9AEBCAD28C0CCB5BFBCF6295F F6F6B696E672E687770>

SRC PLUS 제어기 MANUAL

untitled

PRO1_09E [읽기 전용]

Analytics > Log & Crash Search > Unity ios SDK [Deprecated] Log & Crash Unity ios SDK. TOAST SDK. Log & Crash Unity SDK Log & Crash Search. Log & Cras

1

PowerPoint 프레젠테이션

=

Dialog Box 실행파일을 Web에 포함시키는 방법

chap7.key

Microsoft PowerPoint - a6.ppt [호환 모드]

제목

01-OOPConcepts(2).PDF

Microsoft PowerPoint - a5a.ppt [호환 모드]

Microsoft Word - Heap_Spray.doc

T100MD+

C++-¿Ïº®Çؼ³10Àå

PowerPoint 프레젠테이션

chapter4

chap01_time_complexity.key

BMP 파일 처리

À©µµ³×Æ®¿÷ÇÁ·Î±×·¡¹Ö4Àå_ÃÖÁ¾

untitled

C# Programming Guide - Types

MPLAB C18 C

MAX+plus II Getting Started - 무작정따라하기

11강-힙정렬.ppt

No Slide Title

bn2019_2

초보자를 위한 C++

Microsoft Word - ExecutionStack

Microsoft PowerPoint - ch09 - 연결형리스트, Stack, Queue와 응용 pm0100

휠세미나3 ver0.4

PowerPoint 프레젠테이션

Orcad Capture 9.x

02( ) CSTV11-22.hwp

chap10.PDF

PowerPoint 프레젠테이션

DocsPin_Korean.pages

10.

Microsoft Word - ASG AT90CAN128 모듈.doc

chap 5: Trees

Interstage5 SOAP서비스 설정 가이드

The Self-Managing Database : Automatic Health Monitoring and Alerting


, ( ),, ( ), 3, int kor[5]; int eng[5]; int Microsoft Windows 4 (ANSI C2 ) int kor[5] 20 # define #define SIZE 20 int a[10]; char c[10]; float

歯9장.PDF

Something that can be seen, touched or otherwise sensed

11 템플릿적용 - Java Program Performance Tuning (김명호기술이사)

PRO1_04E [읽기 전용]

歯처리.PDF

Embeddedsystem(8).PDF

4.18.국가직 9급_전산직_컴퓨터일반_손경희_ver.1.hwp

호랑이 턱걸이 바위

USER GUIDE

슬라이드 1

MasoJava4_Dongbin.PDF

04_오픈지엘API.key

목차 BUG offline replicator 에서유효하지않은로그를읽을경우비정상종료할수있다... 3 BUG 각 partition 이서로다른 tablespace 를가지고, column type 이 CLOB 이며, 해당 table 을 truncate

Remote UI Guide

Microsoft Word - FS_ZigBee_Manual_V1.3.docx

슬라이드 1

VOL /2 Technical SmartPlant Materials - Document Management SmartPlant Materials에서 기본적인 Document를 관리하고자 할 때 필요한 세팅, 파일 업로드 방법 그리고 Path Type인 Ph

1.hwp

10X56_NWG_KOR.indd

SIGPLwinterschool2012

Microsoft PowerPoint - 3ÀÏ°_º¯¼ö¿Í »ó¼ö.ppt

목차 BUG DEQUEUE 의 WAIT TIME 이 1 초미만인경우, 설정한시간만큼대기하지않는문제가있습니다... 3 BUG [qp-select-pvo] group by 표현식에있는컬럼을참조하는집합연산이존재하지않으면결괏값오류가발생할수있습니다... 4

Transcription:

Windows System Programming 교재 Sample 아임구루 부설 아이오 교육센터 ( www.ioacademy.co.kr )

SECTION 01 어셈블리 언어와 C언어의 원리 요즘은 어셈블리언어를 거의 사용하지 않고 C/C++/Java 등의 고급 언어를 사용합니다. 하지만 간단 한 어셈블리어를 읽고 이해 할 수 있다면 시스템에 대해 보다 깊이 있게 이해를 할 수 있게 됩니다. TEB, PEB 접근 등 다양한 윈도우 시스템 고급 기법을 이해 하기 위해서 약간의 어셈블리에 대한 지 식은 반드시 필요합니다. 또한 함수호출의 원리, Calling Convention, 지역 변수의 원리 등 C/C++의 근본적인 원리를 정확히 이해 할 수 있습니다. 주요 내용 어셈블리 언어의 기본 코드를 이해 하고 C 함수와 어셈블리 함수를 상호 호출하는 방법을 학습 합니다. 함수 호출의 정확한 원리를 이해하고 다양한 함수 호출규약(Calling Convention)을 정확히 이해하고 각각의 방식의 장단점을 학습 합니다. 인라인 어셈블리를 사용해서 TEB, PEB 등의 윈도우 구조체에 접근하는 방법을 학습 합니다. OllyDbg 를 사용해서 간단한 Crack, Reversing 방법을 학습 합니다. 1

Item 1 01 PE Format 핵심개념 PE Format 의 구조 IMAGE_NT_HEADERS( IMAGE_FILE_HEADER, IMAGE_OPTIONAL_HEADER) Sections PEview.exe 사용자 정의 섹션 만들기 1. 실행파일의 구조 Portable Executable File Format 2

2. 실행파일 헤더 PE 구조 IMAGE_DOS_HEADER MS DOS Stub IMAGE_NT_HEADERS IMAGE_SECTION_HEADER Signature IMAGE_FILE_HEADER IMAGE_OPTIONAL_HEADER MS DOS 시절에 사용하던 헤더 현재는 사용되지 않는다. 항상 PE 로 되어 있다. Machine종류, 날짜등 가장 중요한 헤더 AddressOfEntry, Image Base Stack, Heap 크기등의 정보를 가진다 각 Section의 정보를 담고 있다. Section의 개수만큼 존재한다. 3. Sections 실행 파일은 PE 헤더 다음으로 Section 이라는 요소로 구분된다. 대부분의 표준 Section 은. 으로 시작한다. Section Name.bss.CRT.data.debug.didata.edata.idata.rdata.reloc.rsrc.text.tls.xdata Purpose Uninitialized data Read-only C run-time data Initialized data Debugging information Delay imported names table Exported names table Imported names table Read-only run-time data Relocation table information Resources Code Thread-Local-Storage Exception Handling Table 3

4. PEView http://wjradburn.com/software/ #include <stdio.h> char s[] = "abcdefg"; void main() printf("hello, world\n"); 5. 사용자 정의 섹션 추가 하기 #pragma data_seg() #pragma code_seg() char s1[] = "abcdefg"; #pragma data_seg("mydata") char s2[] = "opqrstu"; #pragma data_seg() #pragma code_seg("mycode") void foo() #pragma code_seg() void main() 4

Item 1 02 함수 호출의 원리 1 핵심개념 함수 호출의 원리 마지막 인자부터 stack 에 넣고 함수로 이동 함수의 반환 값은 EAX 레지스터를 사용 asm 키워드로 인라인 어셈블리 사용하기 1. 함수 호출과 stack 구조 #include <stdio.h> #include <stdlib.h> void goo() printf("goo\n"); exit(0); void foo( int a, int b) int x = 10; int y[2]=0,0; y[2] = 20; printf("%d\n", x); // A y[4] = (int)goo; // B return; void main() int a = 10; foo( 1,2); int a = 10 10 foo(1,2) 2 1 Return Address EBP int x = 10 10 int y[2] 0 0 Stack High Address Growing Stack Low Address 5

2. 인라인 어셈블리 사용하기 asm 키워드를 사용한 인라인 어셈블리 int Add(int a, int b) int c = a + b; return c; int main() int n = 0; Add(1,2); asm mov n, eax printf("%d\n", n); int Add(int a, int b) int c = a + b; asm mov int main() int n = 0; n = Add(1,2); eax, c printf("%d\n", n); 6

Item 1 03 Hello, Assembly 핵심개념 어셈블리 소스의 이해 http://www.nasm.us 어셈블리 기본 코드 전역변수 사용하기 Compile & Linking Console 창에서 Command Line 컴파일 하기 VC++과 nasm 의 연동 1. Hello, Assembly cl main.c /c nasm f win32 o first. obj first.asm link main.obj first.obj main.c first.asm #include <stdio.h> int asm_main(); segment segment.data.text int main() int n = asm_main(); _asm_main: global _asm_main printf("결과 : %d\n", n); mov eax, 10 ret 7

2. nasm 과 VC++ 연동하기 first.asm 에서 오른쪽 버튼 => 속성 메뉴 선택 항목 형식에서 사용자 지정 빌드 선택후 적용 버튼 사용자 지정 빌드 도구 선택후 명령줄 / 출력 항목에 추가 8

3. 어셈블리에서 전역변수 사용하기 segment.data 전역변수 레이블(L1)은 주소의 의미 주소가 가르키는 값을 꺼내려면 dword [L1] MASM 의 경우 dword ptr[l1] segment.data L1 DD 100 ; int L1 = 100, DD : Define DWORD L2 DW 10 ; short L2 = 10 L3 DB "hello", 0 ; char L3[] = "hello" segment.text _asm_main: global _asm_main mov dword [L1], 200 ; NASM : dword [L1], MASM : dword ptr[l1] mov eax, dword [L1] ; L1은 주소, [L1] 은 값. ret 9

Item 1 04 함수 호출의 원리 2 핵심개념 Jmp 를 사용한 함수 호출 - 돌아올 주소를 알려 주어야 한다. 레지스터를 통해서 돌아올 주소를 알려 주는 방식 스택을 통해서 돌아올 주소를 알려 주는 방식 call, ret 을 사용한 함수 호출 1. jmp 를 사용한 함수 호출 레지스터에 돌아올 주소를 담아서 전달 stack 에 돌아올 주소를 담아서 전달 _asm_main: mov jmp A: ret foo: ebx, A foo mov eax, 20 jmp ebx _asm_main: push A jmp foo A: ret foo: mov eax, 20 pop ebx jmp ebx 2. call / ret 를 사용한 함수 호출 Jmp 의 stack 버전 _asm_main: call ret foo: ret foo 10

Item 1 05 함수 인자 전달 방식 핵심개념 레지스터를 통한 인자 전달 ECX, EDX 레지스터 사용 스택을 통한 인자 전달 인자 전달용 스택을 파괴해야 한다. 호출 자(Caller)가 파괴 하는 방식 피호출자(Callee)가 파괴 하는 방식 레지스터 vs 스택 의 장단점 1. 레지스터를 사용한 인자 전달 방식 ECX, EDX 레지스터를 사용해서 인자 전달 속도는 빠르지만 인자 개수에 제한이 있다. _asm_main: mov edx, 20 mov ecx, 10 call ret foo foo: mov eax, ecx ; eax = ecx add eax, edx ; eax += edx ret 11

2. Stack 을 사용한 인자 전달 방식 ESP 레지스터에 가장 최근에 사용한 스택의 주소에 있음. 왜 Runtime Error 가 발생하는가? Stack 구조가 중요 _asm_main: push 20 push 10 call foo ret main() stack main() 으로 돌아갈 주소 foo: mov add ret eax, dword[esp+4] eax, dword[esp+8] _asm_main() stack 20 10 _asm_main() 으로 돌아갈 주소 ESP foo() stack stack 인자 전달에 사용한 stack 은 반드시 파괴 되어야 한다. 3. 인자 전달용 Stack 의 파괴 호출자(caller) 파괴 방식 피호출자(callee) 파괴 방식 _asm_main: push 20 push 10 call foo foo: sub esp, 8 ret mov add ret eax, dword[esp+4] eax, dword[esp+8] _asm_main: push 20 push 10 call foo ret foo: mov add ret 8 eax, dword[esp+4] eax, dword[esp+8] 장점 : 단점 : 장점 : 단점 : 12

Item 1 06 Stack Frame 핵심개념 EBP 레지스터를 사용한 Stack 관리 dword ptr [ebp+8] : 함수의 1 번째 인자 dword ptr [ebp-4] : 함수의 1 번째 지역변수 지역 변수의 원리 함수 Prolog 와 Epilog 1. Stack Frame EBP 레지스터를 사용해서 함수 인자 및 지역변수에 접근한다. 함수 시작시 EBP 의 현재값을 보관했다가 함수 종료 직전에 복구 해 준다. 함수 안에서 Stack 사용시 ESP 는 변하지만 EBP 는 변하지 않는다. 고정된 offset 으로 함수 인자에 접근할 수 있다.(EBP+8, EBP+12) _asm_main: foo: push 20 push 10 call foo add esp, 8 ret push mov mov add pop ebp ebp, esp eax, dword[ebp+8] eax, dword[ebp+12] ebp main() stack _asm_main() stack foo() stack main() 으로 돌아갈 주소 20 10 _asm_main() 으로 돌아갈 주소 EBP 예전값 EBP ESP ret stack 13

2. 지역변수 사용하기 필요한 만큼의 stack 공간을 확보 : add esp, 필요한 지역변수 크기 EBP 레지스터를 사용해서 접근 : EBP 4 함수 호출 종료 시 지역변수가 사용하던 stack 은 파괴 되어야 한다 _asm_main: push 20 push 10 call foo add esp, 8 ret foo: push ebp mov ebp, esp sub esp, 8 ; int x, y mov dword[ebp-4], 1 ; x = 1 mov dword[ebp-8], 2 ; y = 2 mov add eax, dword[ebp+8] eax, dword[ebp+12] main() stack _asm_main() stack foo() stack main() 으로 돌아갈 주소 20 10 _asm_main() 으로 돌아갈 주소 EBP 예전값 EBP 1 x 2 y ESP mov pop ret esp, ebp ; 지역변수 파괴 ebp stack 3. Prolog / Epilog foo: ; Prolog push ebp mov ebp, esp sub esp, 8 ; Epilog mov esp, ebp pop ebp ret 14

Item 1 07 Coding High Level, Thinking Low Level 핵심개념 C 언어가 만드는 어셈블리 코드 예측하기 cl sample.c /FAs 로 어셈블리 소스 확인 하기 1. cl 컴파일러로 어셈블리 소스 확인 하기 /FAs 옵션을 사용해서 어셈블리 소스 확인 하기 cl sample.c /FAs notepad sample.asm int Add(int a, int b) int c = 0; c = a + b; return c; int main() int n = Add(1, 2); 2. cl 컴파일러 옵션 /FAs : 어셈블리 소스를 만들기 /Ob1 : 인라인 치환 적용 /O2 : 최적화 적용 /help : 도움말 15

Item 1 08 Calling Convention 핵심개념 Calling Convention 의 정확한 개념 어셈블리 언어에서의 C 함수를 호출 하는 방법 1. Calling Convention 함수 인자가 어디를 통해서 전달되는가? 인자 전달용 stack 은 누가 파괴하는가? 함수 이름은 어떻게 변경 되는가? Calling Convention Argument Passing Stack Maintenance Name Decoration Notes cdecl Stack Right -> Left 호출자(Caller) _함수이름() ex) _foo C/C++함수의 기본 호출규약 stdcall Sack Right -> Left 피호출자(Callee) _함수이름@인자크기 ex) _foo@12 Win32 API Visual Basic 2개까지는 ECX, EDX레지스터 fastcall 사용 나머지는 Stack 피호출자(Callee) @함수이름@인자크기 ex) @foo@12 Intel CPU Right -> Left This Stack Right -> Left this가 ecx레지스터로 전달 호출자(Caller) C++클래스 COM naked Stack Right -> Left 호출자(Caller) 드라이버 개발 Custom Epilog/Prolog 제작 16

2. 어셈블리 소스로 Calling Convention 확인 main2.c main2.asm #include <stdio.h> void f1(int a, int b) _main PROC push mov ebp ebp, esp void stdcall f2(int a, int b) void fastcall f3(int a, int b) void fastcall f4(int a, int b, int c) int main() f1(1, 2); f2(1, 2); f3(1, 2); f4(1, 2, 3); ; f1(1, 2) push 2 push 1 call _f1 add esp, 8 ; f2(1, 2) push 2 push 1 call _f2@8 ; f3(1, 2) mov edx, 2 mov ecx, 1 call @f3@8 ; f4(1, 2, 3) push 3 mov edx, 2 mov ecx, 1 call @f4@12 17

3. 어셈블리 소스에서 C 함수 호출하기 사용자 정의 함수 호출 C 표준 함수 호출 Win32 API 호출 #include <stdio.h> int asm_main(); int main() asm_main(); void cdecl f1(int a, int b) printf("f1 : %d, %d\n", a, b); void stdcall f2(int a, int b) printf("f2 : %d, %d\n", a, b); void fastcall f3(int a, int b) printf("f3 : %d, %d\n", a, b); void fastcall f4(int a, int b, int c) printf("f4 : %d, %d, %d\n", a, b, c); segment.data S1 DB "hello", 10, 0 ; "hello/n" segment.text global _asm_main extern _f1 extern _f2@8 extern @f3@8 extern @f4@12 extern _printf extern _MessageBoxA@16 _asm_main: ; f1(1,2) push 2 push 1 call _f1 add esp, 8 ; f2(1,2) push 2 push 1 call _f2@8 ; f3(1,2) mov edx, 2 mov ecx, 1 call @f3@8 ; f4(1,2,3) push 3 mov edx, 2 mov ecx, 1 call @f4@12 ; printf("hello\n") push S1 call _printf add esp, 4 ; MessageBoxA(0, S1, S1, MB_OK) push 0 push S1 push S1 push 0 call _MessageBoxA@16 ret 18

Item 1 09 반복문과 제어문 핵심개념 FLAG 레지스터 Loop 명령과 ECX 레지스터 1. 반복문 LOOP 명령과 ECX 레지스터 #include <stdio.h> int asm_main(); int main() int n = asm_main(); printf("결과 : %d\n", n); segment.text global _asm_main _asm_main: mov ecx, 10 mov eax, 0 AAA: add eax, ecx ; eax += ecx loop AAA ; if ( --ecx!= 0 ) ; goto AAA ret 2. LOOP OPCODE LOOP Loop With ECX counter LOOPZ/LOOPNZ Loop With ECX and zero ( not zero ) LOOPE/LOOPNE Loop With ECX and equal ( not equal ) 19

3. FLAG 레지스터 연산의 결과에 따라 각 비트가 set/reset 되는 레지스터 4. FLAG 레지스터와 조건부 JMP EFLAG 레지스터의 상태에 따라 조건부 JMP를 하는 OPCODE segment.text _asm_main: global _asm_main mov ecx, 10 mov eax, 0 AAA: mov ebx, ecx and ebx, 1 ; 의미는? jz BBB ; if ( ZF == 1 ) jmp BBB add eax, ecx ; eax += ecx BBB: loop AAA ; if ( --ecx!= 0 ) goto AAA ret 20

5. Conditional JMP OPCODE 조건에 따라 JMP를 수행하는 OPCODE JMP Jump JE/JNE Jump if equal (not equal ) JZ/JNZ Jump if zero ( not zero ) JA/JNA Jump if above ( not above ) JAE/JNAE Jump if above or equal ( not above or equal ) JB/JNB Jump if below ( not below) JBE/JNBE Jump if below or equal ( not below or equal ) JG/JNG Jump if greater ( not greater ) JGE/JNGE Jump if greater or equal ( not greater or equal ) JL/JNL Jump if less ( not less ) JLE/JNLE Jump if less or equal ( not less or equal ) JC/JNC Jump if carry ( not carry ) JO/JNO Jump if overflow ( not overflow ) JS/JNS Jump if sign ( not sign ) JPO/JPE Jump if parity odd ( even ) JP/JNP Jump if parity ( not parity ) JCXZ/JECXZ Jump if register CX zero ( ECX zero ) 21

Item 1 10 Reversing With OllyDbg 핵심개념 OllyDbg 사용법 http://www.ollydbg.de/ Break Pointer when API call Code Memory, Data Memory, Stack, Register 1. CrackMe PEView 를 사용해서.data,.rdata 섹션 조사 OllyDbg 를 사용해서 Reversing 2. Using OllyDbg Breakpoints when API call Step 1. 툴바에서 E 버튼 클릭 22

Step 2. 실행파일을 선택하고 오른쪽 버튼 클릭, Show names 메뉴 선택 Step 3. GetWindowTextA 함수를 찾아서 오른쪽 버튼 클릭, Find Reference 메뉴 선택 Step 4. 함수 호출 구문에서 오른쪽 버튼 클릭, BreakPoint 메뉴 선택 Step 5. 빨간색으로 변경되었는지 확인 23

Item 1 11 Assembly 활용 핵심개념 인라인 어셈블리를 활용한 윈도우 구조체 접근 TEB, PEB 의 주소 얻어내기 GetLastError() 구현하기 현재 프로세스의 디버깅여부 알아내기 1. TEB(Thread Environment Block) 과 FS 레지스터 스레드당 1개의 구조체, FS 레지스터로 TEB의 주소관리 Position Length OS Versions Description FS:[0x00] 4 Win9x and NT Current Structured Exception Handling (SEH) frame FS:[0x04] 4 Win9x and NT Stack Base / Bottom of stack (high address) FS:[0x08] 4 Win9x and NT Stack Limit / Ceiling of stack (low address) FS:[0x0C] 4 NT SubSystemTib FS:[0x10] 4 NT Fiber data FS:[0x14] 4 Win9x and NT Arbitrary data slot FS:[0x18] 4 Win9x and NT Linear address of TIB ---- End of NT subsystem independent part ---- FS:[0x1C] 4 NT Environment Pointer FS:[0x20] 4 NT Process ID (in some windows distributions this field is used as 'DebugContext') FS:[0x24] 4 NT Current thread ID FS:[0x28] 4 NT Active RPC Handle FS:[0x2C] 4 Win9x and NT Linear address of the thread-local storage array FS:[0x30] 4 NT Linear address of Process Environment Block (PEB) FS:[0x34] 4 NT Last error number FS:[0x38] 4 NT Count of owned critical sections FS:[0x3C] 4 NT Address of CSR Client Thread FS:[0x40] 4 NT Win32 Thread Information FS:[0x44] 124 NT, Wine Win32 client information (NT), user32 private data (Wine), 0x60 = LastError (Win95), 0x74 = LastError (WinME) FS:[0xC0] 4 NT Reserved for Wow64. Contains a pointer to FastSysCall in Wow64. FS:[0xC4] 4 NT Current Locale 24

FS:[0xC8] 4 NT FP Software Status Register FS:[0xCC] 216 NT, Wine Reserved for OS (NT), kernel32 private data (Wine) herein: FS:[0x124] 4 NT Pointer to KTHREAD (ETHREAD) structure FS:[0x1A4] 4 NT Exception code FS:[0x1A8] 18 NT Activation context stack FS:[0x1BC] 24 NT, Wine Spare bytes (NT), ntdll private data (Wine) FS:[0x1D4] 40 NT, Wine Reserved for OS (NT), ntdll private data (Wine) FS:[0x1FC] 1248 NT, Wine GDI TEB Batch (OS), vm86 private data (Wine) FS:[0x6DC] 4 NT GDI Region FS:[0x6E0] 4 NT GDI Pen FS:[0x6E4] 4 NT GDI Brush FS:[0x6E8] 4 NT Real Process ID FS:[0x6EC] 4 NT Real Thread ID FS:[0x6F0] 4 NT GDI cached process handle FS:[0x6F4] 4 NT GDI client process ID (PID) FS:[0x6F8] 4 NT GDI client thread ID (TID) FS:[0x6FC] 4 NT GDI thread locale information FS:[0x700] 20 NT Reserved for user application FS:[0x714] 1248 NT Reserved for GL FS:[0xBF4] 4 NT Last Status Value FS:[0xBF8] 532 NT Static UNICODE_STRING buffer FS:[0xE0C] 4 NT Pointer to deallocation stack FS:[0xE10] 256 NT TLS slots, 4 byte per slot FS:[0xF10] 8 NT TLS links (LIST_ENTRY structure) FS:[0xF18] 4 NT VDM FS:[0xF1C] 4 NT Reserved for RPC FS:[0xF28] 4 NT Thread error mode (RtlSetThreadErrorMode) 2. TEB 와 PEB 의 주소 얻기 FS:[0x18], FS:[0x30] #include <stdio.h> #include <Windows.h> void* GetTEBAddr() void* pteb = 0; asm mov eax, dword ptr FS:[0x18] mov pteb, eax return pteb; void* GetPEBAddr() 25

void* ppeb = 0; asm mov eax, dword ptr FS : [0x30] mov ppeb, eax return ppeb; int main() printf("current Thread TEB Address : %p\n", GetTEBAddr()); printf("current Thread PEB Address : %p\n", GetPEBAddr()); 3. GetLastError() 원리 스레드당 한 개의 에러 코드 TEB 의 Offset 0x34. #include <stdio.h> #include <Windows.h> int MyGetLastError() int value = 0; asm mov eax, dword ptr FS : [0x34] mov value, eax return value; int main() HWND h = CreateWindow(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); if (h == 0) printf("실패 : %d\n", GetLastError()); printf("실패 : %d\n", MyGetLastError()); 26

SECTION 02 Kernel Object Windows OS는 대부분의 구성요소를 구조체를 사용해서 관리하는 객체 기반 OS입니다. Windows OS가 만드는 객체는 크게 User Object, GDI Object, Kernel Object 로 구분 합니다. 이중 Kernel Object 는 시스템의 기능을 수행하는 객체로서 다양한 특징을 가지고 있습니다. 본 섹션에서는 Kernel Object의 다양한 특징을 이해하고 관련 기술을 학습합니다. 주요 내용 핸들의 개념을 이해하고 윈도우 핸들을 얻고 핸들을 사용해서 기존 윈도우의 다양한 속성을 변경하는 기법을 학습 합니다. User Object, GDI Object, Kernel Object 의 각각의 특징을 학습 합니다.. Kernel Object 를 관리하는 Object Table 을 학습 합니다. 두 개 이상의 Process 간에 Kernel Object 를 공유하는 3 가지 기술을 학습 합니다. 27

Item 2 01 Handle 과 Window 핵심개념 객체를 구별하는 32/64 비트 정수 핸들과 타입 안정성 SetWindowLong / GetWindowLong 을 사용한 Window Object 조작 1. Handle 의 개념 객체(윈도우, 펜, 브러시, 폰트등)를 구별하기 위한 고유한 번호 32/64 비트 정수 핸들을 알면 윈도우를 조작할 수 있다. Win32 API = 객체의 고유한 번호(핸들) + 핸들을 가지고 객체를 조작하는 함수 #include <Windows.h> #include <stdio.h> #include <conio.h> int main() HWND hwnd = FindWindowA(0, "계산기"); printf("계산기 윈도우 번호(핸들): %x\n", hwnd); _getch(); MoveWindow(hwnd, 0, 0, 300, 300, TRUE); _getch(); ShowWindow(hwnd, SW_HIDE); _getch(); ShowWindow(hwnd, SW_SHOW); _getch(); SetMenu(hwnd, 0); HRGN h = CreateEllipticRgn(0, 0, 300, 300); _getch(); SetWindowRgn(hwnd, 0, TRUE); 28

2. 핸들의 정체 구조체 포인터를 사용해서 서로 다른 종류의 핸들이 암시적 형 변환을 방지 타입 안정성을 고려한 설계 typedef void* HANDLE; struct HWND int unused;; struct HICON int unused;; typedef HWND *HWND; typedef HICON *HICON; typedef void* HANDLE; void MoveWindow(HWND hwnd, int x, int y, int w, int h) int main() HICON h = 0; MoveWindow(h, 0, 0, 0, 0); Windows.h 에서는 DECLARE_HANDLE( ) 매크로 사용 #define DECLARE_HANDLE(name) \ struct name## int unused;; typedef struct name## *name 3. Window Object 하나의 윈도우를 관리하기 위해 생성되는 객체 Windows 95 System Programing Secrets, matt pietrick typedef struct _WND32 struct _WND32 *hwndnext; // 00h (GW_HWNDNEXT) HWND of next sibling window struct _WND32 *hwndchild; // 04h (GW_CHILD) First child window struct _WND32 *hwndparent; // 08h Parent window handle struct _WND32 *hwndowner; // 0Ch Owning window handle RECTS rectwindow; // 10h Rectangle describing entire window RECTS rectclient; // 18h Rectangle for client area of window WORD hqueue; // 20h Application message queue handle WORD hrgnupdate; // 22h window region needing an update WORD wndclass; // 24h handle to an INTWNDCLASS WORD hinstance; // 26h hinstance of creating application WNDPROC lpfnwndproc; // 28h Window procedure address 29

DWORD dwflags; // 2Ch internal state flags DWORD dwstyleflags; // 30h WS_XXX style flags DWORD dwexstyleflags; // 34h WS_EX_XXX extended style flags DWORD moreflags; // 38h flags HANDLE ctrlid; // 3Ch GetDlgCtrlId or hmenu WORD windowtextoffset; // 40h Offset of the window's text in atom heap WORD scrollbar; // 42h DWORD associated with the scroll bars WORD properties; // 44h Handle for first window property WORD hwnd16; // 46h Actual HWND value for this window struct _WND32* lastactive; // 48h Last active owned popup window HANDLE hmenusystem; // 4Ch handle to the system menu DWORD un1; // 50h WORD un2; // 54h WORD classatom; // 56h See also offs. 2 in the field 24 struct ptr DWORD alternatepid; // 58h DWORD alternatetid; // 5Ch WND32, *PWND32; 4. SetWindowLong() / GetWindowLong() Window 구조체를 속성을 변경하는 함수 #include <Windows.h> #include <stdio.h> #include <conio.h> void ModifyStyle(HWND hwnd, UINT remove, UINT add) int style = GetWindowLong(hwnd, GWL_STYLE); style = style add; style = style & ~remove; SetWindowLong(hwnd, GWL_STYLE, style); SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE SWP_NOSIZE SWP_NOZORDER SWP_DRAWFRAME); int main() HWND hwnd = FindWindowA(0, "계산기"); _getch(); ModifyStyle(hwnd, WS_CAPTION, WS_THICKFRAME); _getch(); ModifyStyle(hwnd, WS_THICKFRAME, WS_CAPTION); 30

Item 2 02 Object Category 핵심개념 Object 의 3 가지 종류 와 특징 User Object, GDI Object, Kernel Object Kernel Object 의 특징 1. 프로세스간 핸들 공유 Window, Pen, File 핸들의 공유 문제 31

2. Object Category Windows OS가 만드는 Object 의 3가지 종류 User Object GDI Object Kernel Object 특징 윈도우와 관련된 Object. 그래픽 관련된 Object. 파일, 메모리, 프로세스, IPC 등과 같은 작업에 관련된 Object. 핸들의 특징 Public to All Process Private 상대적(Specific) 핸들 파괴함수 DestroyXXX() DeleteXXX() CloseHandle() 참조계수 감소 관련 DLL User32.dll GDI32.dll Kernel32.dll Accelerator table, Caret, Bitmap, Brush, DC, Access token, Change notification, Cursor, DDE Enhanced metafile, Communications, device, Console input, conversation, Hook, Enhanced-metafile DC, Console screen buffer, Desktop, Icon, Menu, Window, Font, Memory DC, Event,Event log, File, File mapping, 종류 Window position Metafile, Metafile DC, Heap, Job, Mailslot, Module, Mutex, Palette, Pen and Pipe, Process, Semaphore, Socket, extended pen, Region Thread, Timer, Timer queue, Timerqueue timer, Update resource, Window station 3. Kernel Object 특징 보안속성, 이름, 참조계수, Signal, WaitList 보안속성 이름 참조계수 Signal Wait List 32

Item 2 03 Kernel Object Handle Table 핵심개념 EPROCESS 와 Object Table Process Explorer Object Table 조사 하기 Native API 를 사용해서 Object Table 열거 하기 1. Process s Object Table 프로세스가 사용하는 Kernel Object 의 핸들을 관리 하는 Table User Object 와 GDI Object 는 포함되지 않는다. 33

2. Process Explorer Utility https://technet.microsoft.com/ko-kr/sysinternals/bb896653.aspx #include <Windows.h> #include <stdio.h> #include <conio.h> int main() _getch(); HANDLE hevent = CreateEventA( 0, 0, 0, "MYEVENT"); printf("event 핸들 : %x\n", hevent); _getch(); HANDLE hmutex = CreateMutexA( 0, 0, "MYMUTEX"); printf("mutex 핸들: %x\n", hmutex); _getch(); HANDLE hsemaphore = CreateSemaphoreA( 0, 0, 3, "MYSEMAPHORE"); printf("semaphore 핸들: %x\n", hsemaphore); _getch(); CloseHandle( hevent); _getch(); CloseHandle( hmutex); _getch(); CloseHandle( hsemaphore); 34

3. Native API 를 사용한 Object Handle Table 열거 하기 ZwQuerySystemInformation를 사용한 Process Object Table 열거 #include <stdio.h> #include <Windows.h> #include <conio.h> #define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) typedef enum _SYSTEM_INFORMATION_CLASS SystemBasicInformation, // 0 SystemProcessorInformation, // 1 SystemPerformanceInformation, // 2 SystemTimeOfDayInformation, // 3 SystemNotImplemented1, // 4 SystemProcessesAndThreadsInformation, // 5 SystemCallCounts, // 6 SystemConfigurationInformation, // 7 SystemProcessorTimes, // 8 SystemGlobalFlag, // 9 SystemNotImplemented2, // 10 SystemModuleInformation, // 11 SystemLockInformation, // 12 SystemNotImplemented3, // 13 SystemNotImplemented4, // 14 SystemNotImplemented5, // 15 SystemHandleInformation, // 16 SystemObjectInformation, // 17 SystemPagefileInformation, // 18 SystemInstructionEmulationCounts, // 19 SystemInvalidInfoClass1, // 20 SystemCacheInformation, // 21 SystemPoolTagInformation, // 22 SystemProcessorStatistics, // 23 SystemDpcInformation, // 24 SystemNotImplemented6, // 25 SystemLoadImage, // 26 SystemUnloadImage, // 27 SystemTimeAdjustment, // 28 SystemNotImplemented7, // 29 SystemNotImplemented8, // 30 SystemNotImplemented9, // 31 SystemCrashDumpInformation, // 32 SystemExceptionInformation, // 33 SystemCrashDumpStateInformation, // 34 SystemKernelDebuggerInformation, // 35 SystemContextSwitchInformation, // 36 SystemRegistryQuotaInformation, // 37 SystemLoadAndCallImage, // 38 SystemPrioritySeparation, // 39 SystemNotImplemented10, // 40 SystemNotImplemented11, // 41 SystemInvalidInfoClass2, // 42 SystemInvalidInfoClass3, // 43 SystemTimeZoneInformation, // 44 SystemLookasideInformation, // 45 SystemSetTimeSlipEvent, // 46 35

SystemCreateSession, // 47 SystemDeleteSession, // 48 SystemInvalidInfoClass4, // 49 SystemRangeStartInformation, // 50 SystemVerifierInformation, // 51 SystemAddVerifier, // 52 SystemSessionProcessesInformation // 53 SYSTEM_INFORMATION_CLASS; typedef struct _SYSTEM_HANDLE_INFORMATION ULONG ProcessId; UCHAR ObjectTypeNumber; UCHAR Flags; USHORT Handle; PVOID Object; ACCESS_MASK GrantedAccess; SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION; typedef NTSTATUS ( stdcall *F)(SYSTEM_INFORMATION_CLASS,PVOID,ULONG,PULONG); F ZwQuerySystemInformation = 0; int main() HMODULE hdll = GetModuleHandleA("Ntdll.dll"); ZwQuerySystemInformation = (F)GetProcAddress(hDll, "ZwQuerySystemInformation"); int sz = sizeof(system_handle_information); int count = 30000; void* buff = malloc(sz * count + 4); DWORD len; DWORD ret = ZwQuerySystemInformation(SystemHandleInformation, buff, sz * count + 4, &len); if (ret == STATUS_INFO_LENGTH_MISMATCH) printf("버퍼가 작습니다..\n"); int n = *(int*)buff; printf("핸들 테이블 항목 개수 : %d\n", n); SYSTEM_HANDLE_INFORMATION* phandle = (SYSTEM_HANDLE_INFORMATION*)((char*)buff + 4); for (int i = 0; i < n; i++) printf("pid : %d, HANDLE : %x, TYPE : %d\n", phandle[i].processid, phandle[i].handle, phandle[i].objecttypenumber); 36

Item 2 04 프로세스간 Kernel Object 공유 1 DuplicateHandle 핵심개념 프로세스간 Kernel Object Handle 을 복사하는 방법 DuplicateHandle() 함수 사용법 1. 프로세스간 Kernel Object Handle 의 핸들 복사 개념 37

2. DuplicateHandle()을 사용한 Object Handle 복사 예제 A Process #include <stdio.h> #include <windows.h> #include <conio.h> int main() HANDLE hfile = CreateFileA("a.txt", GENERIC_READ GENERIC_WRITE, FILE_SHARE_READ FILE_SHARE_WRITE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); printf("file Handle : %x\n", hfile); _getch(); HWND hwnd = FindWindow(0, "B"); DWORD pid; DWORD tid = GetWindowThreadProcessId(hwnd, &pid); HANDLE hprocess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid); HANDLE h2; DuplicateHandle(GetCurrentProcess(), hfile, hprocess, &h2, 0, 0, DUPLICATE_SAME_ACCESS); printf("b 프로세스에 복사해준 핸들(table index) : %x\n", h2); _getch(); SendMessage(hwnd, WM_APP + 100, 0, (LPARAM)h2); B Process GUI Application case WM_APP + 100: HANDLE hfile = (HANDLE)lParam; char s[256] = "hello"; DWORD len; BOOL b = WriteFile(hFile, s, 256, &len, 0); MessageBoxA( 0, b? "성공":"실패", "", 0); return 0; 38

Item 2 05 프로세스간 Kernel Object 공유 2 Named Object 핵심개념 CreateXXX() 함수와 OpenXXX() 함수의 차이점 ERROR_ALREADY_EXISTS Kernel Object 에 상관없이 같은 이름 공간을 사용 1. 실행파일의 구조 동일한 이름의 Kernel Object 는 하나 이상 만들 수 없다. 해당 이름의 Kernel Object 가 이미 존재 할 경우 Open 2번 이상 실행 #include <Windows.h> #include <stdio.h> #include <conio.h> int main() HANDLE hevent = CreateEventA( 0, 0, 0, "MYEVENT"); if ( GetLastError() == ERROR_ALREADY_EXISTS ) printf("open Event Handle\n"); else printf("create Event\n"); _getch(); 39

2. Create vs Open Create : 해당 이름의 객체가 없으면 생성, 이미 존재하면 오픈 Open : 해당 이름의 객체가 없으면 실패, 이미 존재하면 오픈 Kernel Object 의 종류가 달라도 같은 이름을 사용하면 안된다. HANDLE h1 = OpenEventA( EVENT_ALL_ACCESS, 0, "MYEVENT"); HANDLE h2 = CreateEventA( 0, 0, 0, "MYEVENT"); HANDLE h2 = CreateEventA( 0, 0, 0, "MYEVENT"); HANDLE h3 = OpenEventA( EVENT_ALL_ACCESS, 0, "MYEVENT"); HANDLE h4 = CreateMutexA(0, 0, "MYEVENT"); // Fail // success! Create // success! but Open // success! Open // fail 40

Item 2 06 프로세스간 Kernel Object 공유 3 Inherit Kernel Object 핵심개념 커널 오브젝트 상속의 개념 상속 가능한 커널 오브젝트를 만드는 2 가지 방법 객체 생성시 SECURITY_ATTRIBUTES 구조체 사용 객체 생성후 SetHandleInformation() 함수 사용 파이프를 사용한 자식 프로세스의 출력을 Redirect 하는 방법 Console Application 의 출력을 윈도우 창으로 보내는 방법 ZwQueryObject() 함수를 사용해서 Kernel Object 의 상속여부 알아내기 1. Kernel Object 상속의 개념 부모 프로세스가 사용하던 커널 오브젝트를 자식 프로세스에게 상속 할 수 있다. CreateProcess()의 5 번째 파라미터를 TRUE 로 전달한다. 상속가능한 커널 오브젝트만 상속할 수 있다 41

2. 상속 가능한 Kernel Object 를 만드는 2 가지 방법 1. 보안 속성을 지정하는 구조체인 SECURITY_ATTRIBUTES 의 binherit 항목을 TRUE 로 설정한 후 Kernel Object 를 생성한다 SECURITY_ATTRIBUTES sa; sa.nlength = sizeof(sa); sa.binherithandle = TRUE; sa.lpsecuritydescriptor = 0; HANDLE hfile = CreateFile(_T("a.txt"), GENERIC_WRITE GENERIC_READ, 0, FILE_SHARE_READ FILE_SHARE_WRITE, &sa, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); 2. 이미 생성된 Kernel Object 에 SetHandleInformation() 함수로 상속가능 여부를 지정한다. HANDLE hfile = CreateFile(_T("a.txt"), GENERIC_WRITE GENERIC_READ, FILE_SHARE_READ FILE_SHARE_WRITE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); SetHandleInformation(hFile, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); 3. Redirect Child Process s stdout Console Application 의 출력을 Window에 출력하는 기술 42

익명의 파이프를 사용해서 자식 프로세스의 출력을 부모 프로세스에 연결한다. 파이프의 쓰기 핸들을 자식 프로세스에 상속 한다. 부모에서는 파이프의 쓰기 핸들을 반드시 닫아야 한다. void ExecutePing( const TCHAR* url, HWND hedit) TCHAR cmd[256] = _T("ping.exe "); _tcscat(cmd, url); HANDLE hreadpipe, hwritepipe; CreatePipe(&hReadPipe, &hwritepipe, 0, 1024); SetHandleInformation(hWritePipe, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); PROCESS_INFORMATION pi = 0; STARTUPINFO si = sizeof(si) ; si.hstdoutput = hwritepipe; si.dwflags = STARTF_USESTDHANDLES; BOOL bret = CreateProcess(0, cmd, 0, 0, TRUE, CREATE_NO_WINDOW, 0, 0, &si, &pi); if (bret) CloseHandle(hWritePipe); while (1) char buffer[1024] = 0 ; DWORD len; ReadFile(hReadPipe, buffer, 1024, &len, 0); if (len <= 0) break; SendMessage(hEdit, EM_REPLACESEL, 0, (LPARAM)buffer); CloseHandle(hReadPipe); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); 4. Kernel Object 의 상속 가능여부 조사하기 Native API 인 ZwQueryObject()를 사용하면 Kernel Object의 상속여부를 조사할 수 있다. #include <Windows.h> #include <tchar.h> #include <stdio.h> 43

typedef enum _OBJECT_INFORMATION_CLASS ObjectBasicInformation, ObjectNameInformation, ObjectTypeInformation, ObjectAllTypesInformation, ObjectHandleInformation OBJECT_INFORMATION_CLASS; typedef struct _OBJECT_HANDLE_ATTRIBUTE_INFORMATION BOOLEAN Inherit; BOOLEAN ProtectFromClose; OBJECT_HANDLE_ATTRIBUTE_INFORMATION, *POBJECT_HANDLE_ATTRIBUTE_INFORMATION; typedef NTSTATUS ( stdcall *PFZwQueryObject) (HANDLE,OBJECT_INFORMATION_CLASS,PVOID,ULONG, PULONG ); int main() PFZwQueryObject ZwQueryObject = (PFZwQueryObject) GetProcAddress( GetModuleHandle(_T("Ntdll.dll")), "ZwQueryObject"); ULONG len; OBJECT_HANDLE_ATTRIBUTE_INFORMATION ohai = 0; HANDLE hevent = CreateEvent( 0, 0, 0, 0 ); SetHandleInformation( hevent, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); ZwQueryObject(hEvent, ObjectHandleInformation, &ohai, sizeof(ohai), &len); printf("inheritable : %d\n", ohai.inherit); SetHandleInformation( hevent, HANDLE_FLAG_INHERIT, 0); ZwQueryObject(hEvent, ObjectHandleInformation, &ohai, sizeof(ohai), &len); printf("inheritable : %d\n", ohai.inherit); 44