2. 목차
• 고급 리버싱 //리버싱 핵심원리 6부
• TLS 콜백 함수 //45장
• 배경지식
• TLS 콜백함수 예제
• TLS 콜백 함수를 이용한 안티 디버깅 예제
• TLS와 PE
• TLS 콜백 함수를 디버깅하는 법
• TEB //46장
• TEB 전체 구조
• 중요 멤버
• PEB //47장
• PEB 전체 구조
• 중요 멤버
• SEH //48장
• 예외 종류
• 간단한 SEH 사용 예
• SEH 원리
• 어셈블리어를 이용한 SEH 설치 + 안티리버싱
• IA-32 Instruction //49장
• 용어 정리
• IA-32 instruction 해석
• 과제
• CodeEngn
• 부록
• 참고 사이트
3. TLS 콜백 함수
• 배 경 지 식
• T L S 콜 백 함 수 예 제
• T L S 콜 백 함 수 를 이 용 한 안 티 디 버 깅 예 제
• T L S 와 P E
• T L S 콜 백 함 수 를 디 버 깅 하 는 법
4. TLS란?
• Thread Local Storage
• 쓰레드 별로 static, global 변수를 독립적으로 만들고 싶을 때 사용
• 일반적인 static, global 변수 : 모든 쓰레드가 공유
• TLS static, global 변수 : 각 쓰레드 내에서만 공유
• TLS 변수 선언 방법
• 정적TLS :
• 동적TLS :
• 쓰레드 safe 라이브러리에서TLS를 이용하는 경우가 많음
• 기존 unsafe한 함수는 전역변수에 저장을 해서 쓰레드 사이에서 공유되었음
5. 콜백 함수란?
• 기본 개념
• 호출자(caller)가 피호출자(callee)를 호출하는 것이 아니라 피호출자가 호출자를 호출하는 것
• 직접 함수를 호출하는 게 아님
• 어떤 상황이 생겼을 때 호출하고 싶은 함수를 등록해 둠
• 그 상황이 생기면 OS가 등록된 함수를 호출해 줌
6. TLS 콜백 함수란?
• 프로세스의 쓰레드가 생성/종료 될 때마다 자동으로 호출되는 함수
• 메인 쓰레드 역시 이 함수를 호출함
• EP보다 먼저 실행됨 -> 안티 디버깅 기법으로 사용됨
• TLS를 사용하도록 프로그래밍 하면TLS 콜백 함수를 등록할 수 있음
• 관련 PE헤더에 내용을 씀
• PE헤더의 자세한 내용은 뒤에서 다룸
7. TLS 콜백 함수 예제
• 간단히 콜백 함수를 이용하는
프로그램을 만들어보자.
• 콜백함수의 인자는 DllMain과
비슷하다
• Reason으로 호출된 이유를
받는다
9. TLS 콜백 함수를 이용한 안티 디버깅
예제
• TLS callback 함수를 이용하여 디버거에서 실행 시 다른 메시지를 띄우도록 한다
10. TLS 콜백 함수를 이용한 안티 디버깅
예제
• TLS callback 함수의 내용만 바꾸면
됨
11. TLS와 PE
• 직접 EXE를 수정하며TLS와 관련된 PE 구조체를 살펴보자
• 관련 헤더
• Optional header의 IMAGE_DATA_DIRECTORY[9]
• TLS table이라는 구조체 배열의 RVA를 가지고 있음
• TLS table
• IMAGE_TLS_DIRECTORY 구조체
• 32비트와 64비트 프로그램은 서로 다른 구조체를 이용
12. TLS와 PE
• StartAddressOfRawData와 EndAddressOfRawData, 그리
고AddressOfIndex, SizeOfZeroFill은 TLS 변수들을 위한
멤버
• PE 심화에서 다룰 것
• 관심있는 멤버는AddressOfCallBacks
• TLS callback 함수포인터 배열의 포인터
• ->여러 개의 callback 함수를 등록할 수 있음
• VA(virtual address) 형태로 쓴다
• 메모리에 올라온 상태의 주소
• (따라서 재배치시 이 필드도 수정해 주어야 함)
13. TLS와 PE
• Callback 함수를 실행하기 위한 순서
• 이 순서를 참고하며 직접 손으로 PE에TLS callback 함수를 추가해보자.
Optional header
data directory[9]
IMAGE_TLS_DIRECTORY AddressOfCallBacks
Callback 함수 주소를 얻어
실행
14. TLS와 PE
• 실험 대상은 ollydbg1이다.
• 기존 프로그램은 데이터 디렉토리를 확인하면 이미TLS table이 있음을 알 수 있다.
• 여기에 앞으로 만들 IMAGE_TLS_DIRECTORY가 있는 RVA가 써 있다.
• 데이터 디렉토리에 적힌 RVA를 따라가면 IMAGE_TLS_DIRECTORY의 내용을 얻을 수 있다
• AddressOfCallBacks를 확인해보면, 50C010이 있다.
• 이는 바로 아래(10C010)를 가리킨다
• ->그 내용이 NULL이므로, NULL배열, 즉 callback함수가 없음을 의미
• 이 필드의 내용을 바꾸면 된다. IMAGE_TLS_DIRECTORY
15. TLS와 PE
• 올리 디버거로 올리 디버거를 열어서 코드 섹션의 빈자리에 callback 함수로 이용될 코드를 쓴다.
• 디버깅을 체크하고 메시지 박스를 띄움
16. • 코드 밑에 함수 시작 주소의VA를 가지고 있는 배열을 만든다
• NULL 배열로 끝을 알려야 한다
• 리틀 엔디안에 주의
TLS와 PE
17. • 함수 포인터의 배열이 위치한VA를 IMAGE_TLS_DIRECTORY 구조체의 AddressOfCallBacks에 써 준다.
TLS와 PE
18. • 이 프로그램을 다시 올리디버거로 돌려보면 메시지 박스를 띄우고 종료한다.
• ->디버깅 방해 (안티 리버싱)
TLS와 PE
19. TLS 콜백 디버깅하는 법
• 디버깅 옵션에서 Make first pause at 설정을 System breakpoint로 설정한다.
• PE 헤더에 써 있는 callback 함수 주소를 이용하여 검색하고 bp를 건다
20. TLS 콜백 디버깅하는 법
• 올리디버거2에는TLS callback부터 시작하는 설정도 있다
22. TEB
• Thread Environment Block
• 각종 고급 디버깅의 기반 지식임
• 쓰레드에 대한 정보를 담고 있는 구조체
• 쓰레드 별로TEB 구조체를 하나씩 저장하고 있음
• OS에 따라 그 모양이 조금씩 다름
• 버전에 따라서도 다름
23. TEB
• 유저모드에서는 세그먼트 레지스터 중 하나인 FS 레지스터가TEB를 가리킴
• 엄밀히 말하면 FS 레지스터가 Segment descriptor table 배열의 인덱스를 저장하고, 해당 배열에는TEB의 주소가 있음
• 올리 디버거에서 DWORD PTR FS:[0x18] 과 같은 코드가TEB 내용에 접근하는 코드이다
24. TEB 전체 구조
• XP의TEB 구조
• 왼쪽에 있는 숫자는 오프셋을 의미한다
• 구조체 시작 주소로부터 얼마나 떨어져 있나
• 이 중 중요한 멤버만 살펴볼 것
26. 중요 멤버
• 살펴볼 멤버
• NtTib
• NT_TIB구조체
• Thread Information Block
• ProcessEnvironmentBlock
• PEB라고 불리는 구조체의 포인터
• PEB는 프로세스별로 하나씩 가지고 있음
• 뒤에서 자세히 설명
27. 중요 멤버
• NT_TIB
• ExceptionList
• _EXCEPTION_REGISTRATION_RECORD 구조체 연결리스트를 가리킴
• SEH(Structured Exception Handler)라고 하는 Windows OS의 예외 처리 메커니즘에 사용
• 뒤에서 자세히 다루겠음, 안티 리버싱에 자주 쓰임
• ExceptionList는 FS:0 위치에 있다
• TEB.NtTib. ExceptionList = TIB 주소 = TEB 주소 = FS:0
• ExceptionList에 접근하기 위해서는 FS:[0] 해야 한다
• 포인터니까!
• Self
• 자기 자신을 가리키는 포인터
• 이는 즉 TEB 구조체의 포인터이기도 함
• TEB구조체의 첫 번째 멤버가 TIB 구조체이기 때문
• Self는 FS:[0x18] 위치에 있다
• TEB.NtTib.Self = TIB의 주소 = TEB의 주소 = FS:[0x18] = FS:0
• FS:0은 FS 레지스터가 인덱싱하는 Segment Descriptor가 가리키는, TEB 시작 주소
0x00
0x04
0x08
0x0C
0x10
0x14
0x18
28. 중요 멤버
• ProcessEnvironmentBlock
• FS:[0x30] 으로 접근해야 함
• 포인터니까!
• 중요한 FS:0, FS:[0]과 FS:[0x18], FS:[0x30]의 의미만 일단 알아 두자
• FS:0
• TEB 시작 주소 = TIB 시작 주소
• FS:[0]
• TEB의 첫 번째 멤버인 SEH와 관련된 주소
• TEB 첫 번째 멤버인 TIB 구조체의 첫 번째 멤버
• FS:[0x18]
• TIB의 주소 = TEB의 주소
• FS:[0x30]
• PEB의 주소
• TEB의 주소를 얻기 위해 Ntdll.NtCurrentTebAPI를 이용한다
• 이 API가 하는 일은 단순히 FS:[0x18]을 반환하는 것이다
30. PEB
• Process Environment Block
• 프로세스의 정보를 담고 있는 구조체
• 프로세스마다 하나씩 가지고 있음
• 각종 고급 디버깅의 기반 지식
• TEB와 마찬가지로OS마다 차이가 있음
• TEB의 ProcessEnvironmentBlock 멤버에 저장된 주소를 이용하여 접근
• FS:[0x30] = PEB 주소
• 중요한 멤버만 살펴볼 것
31. 중요 멤버
• 중요 멤버
• BeingDebugged
• 이 프로세스가 디버기인지(디버깅 당하고 있는지) 표시
• ImageBaseAddress
• 이 프로세스의 ImageBase
• Ldr
32. 중요 멤버
• BeingDebugged
• 이 프로세스가 디버기인지(디버깅 당하고 있는지) 표시
• 1이면 디버깅 당하는 중임을 의미
• Kernel32.IsDebuggerPresent API가 이 멤버를 체크하여 디버깅 중인지를 판단
• FS:[18]에 저장된 TIB의 주소(=TEB의 주소)를 EAX에 저장
• EAX로부터 30 떨어진 주소에 저장된 값 (= FS:[30])을 EAX에 저장 ->PEB 주소
• EAX로부터 2 떨어진 값(PEB.BeingDebugged)을 가져옴
• 1이면 디버깅 당하는 중, 0이면 아님
33. 중요 멤버
• Ldr
• _PEB_LDR_DATA 구조체의 포인터
• 로딩된 DLL의 주소를 얻는 데 이용할 수 있기 때문에 중요하다
• InLoadOrderModuleList, InMemoryOrderModuleList, InInitializationOrderModuleList는 연결 리스트의 주소가 있다
• 세 가지 종류의 연결 리스트
• 로드된 순서, 메모리에 있는 순서, 초기화한 순서
• 양방향 연결리스트이다.
• 각 DLL은 리스트 엔트리를 하나씩 가지고 있다
• 리스트 엔트리는 각 연결 리스트의 적당한 자리에 넣어진다
34. 중요 멤버
• ProcessHeap, NtGlobalFlag
• 프로세스가 디버깅 중이라면 특정한 값을 가진다
• 이를 이용해 안티 리버싱에 활용하곤 한다
• 다음에 자세히 다룰 것
35. SEH
• 예 외 종 류
• 간 단 한 S E H 사 용 예
• S E H 원 리
• 어 셈 블 리 어 를 이 용 한 S E H 설 치 + 안 티 리 버 싱
36. SEH
• Windows 운영체제의 기본 예외 처리 매커니즘
• MS가 만들고,Windows가 씀
• Structured Exception Handler
• 일반적인 예외 처리 기능 외에도 안티 리버싱 기법으로 많이 사용됨
• 일부러 예외를 일으켜서 SEH를 이용하는 등
37. 예외 종류
• 오른쪽은 Windows OS에서 정의한 예외들이다
• 사용자 정의 예외도 만들 수 있지만, 여기서는 자세히 다루지 않겠음
• 디버깅하며 자주 볼 수 있는 예외들을 살펴보자
• EXCEPTION_BREAKPOINT
• bp를 만났을 때 (INT3 명령어)
• EXCEPTION_SINGLE_STEP
• single step이란 명령어 하나를 실행하고 멈추는 것임
• CPU를 single step 모드로 설정했을 시 발생
• EFLAGS 레지스터의 TF 비트를 1로 세팅하면 됨
• 한 명령어를 실행한 후 이 예외를 일으켜 실행을 멈춘다
• EXCEPTION_ACCESS_VIOLATION
• 존재하지 않거나 접근 권한이 없는 메모리 영역에 대해서 접근을 시도할 때
• Ex) NULL 포인터 역참조, write권한이 없는 메모리에 쓰기 시도, 커널 영역 접근 등
• EXCEPTION_ILLEGAL_INSTRUCTION
• CPU가 해석할 수 없는 기계어를 만났을 때
• EXCEPTION_INT_DIVIDE_BY_ZERO
• 정수의 나눗셈에서, 0으로 나누기를 시도했을 때
38. • try에서 예외가 발생하면 except를 실행한다.
• 예외 코드를 확인하여 잘못된 접근(null 포인터 역참조)을 했을
시의 예외를 처리하고 있다
간단한 SEH 사용 예
39. SEH 원리
• SEH는 체인 형태로 구성되어 있다 (리스트)
• SEH가 추가되면 구조체를 리스트에 등록한다
• TEB의 첫 번째 멤버인 NtTib의 첫 번째 멤버인 ExceptionList가 구조체 리스트를 가리킴
• 새로운 SEH는 맨 앞에 들어 감
• 가장 먼저 예외 처리를 시도하는 핸들러가 된다
• 앞의 예외 처리기에서 해당 예외를 처리하지 못하면 처리될 때까지 다음 예외 처리기로 예외를 넘김
• 끝까지 처리하지 못 하면 기본적으로 등록된 OS의 예외 핸들러가 호출되어 예외를 처리
0x00
40. • SEH 체인 예
• 처리할 수 없는 경우에는 다음 SEH를 찾아보도록 코드를 짰다.
• EXCEPTION_CONTINUE_SEARCH
SEH 원리
41. • SEH handler
• 예외 상황, context(예외가 발생한 당시 레지스터 값) 등을 인자로 받아 호출된다
• 예외 상황에는 예외를 일으킨 코드 등 예외와 관련된 정보가 있다
• Context를 백업해 두기 때문에 예외처리 후 다시 되돌아갈 수 있다
• 예외를 발생한 쓰레드는 예외를 처리할 때까지 중지됨
• 백업해둔 Context를 이용하여 복귀 가능
• Context는 스택에 저장 -> Context의 EIP를 바꾸면 쓰레드는 그 주소부터 코드를 실행
• ->안티 리버싱에 이용
• 핸들러는 등록해 둔 코드(__except에 쓴 코드)를 이용하여 예외 처리를 시도한다
• C언어 상에서 try except를 이용하여 SEH를 이용하면 handler 함수가 호출되고, 내부에서 except에 쓴 코드가 호출됨
• 어셈블리어로 등록한다면 직접 만든 handler를 등록할 수 있음
• 핸들러가 호출될 때 받는 인자에도 접근 가능
SEH 원리
42. • 어셈블리어를 이용한 SEH 설치 + 안티 리버싱 1
• 새로운 구조체를 스택에 생성하고, 구조체가 저장된 주소를 리스트의 맨 앞에
추가한다
• FS:[0]
• 반드시 속성-링커-고급-이미지에 안전한 예외 처리기 포함을 해제할 것
• 일부러 예외를 일으키고, SEH에서 안티 리버싱 기법을 사용한
다
• 디버거 감지 뿐만이 아니라 정상 코드를 SEH 내에 넣어서 리버싱을 어렵게 하
기도 함
43. • 어셈블리어를 이용한 SEH 설치 + 안티 리버싱 2
• 앞의 예에서 윗 부분만 변경
• 일부러 예외를 일으키고, SEH에서 안티 리버싱 기법을
사용한다
• SEH에서 정상적인 일을 실행하도록 함
• 응용
• - SEH에서 디버깅 중인지 알아낸 후 디버깅 중이 아니라면 프로그램
을 정상적으로 실행하는 데 반드시 필요한 작업을 하도록 함
• - 시리얼 등이 일치할 경우 예외가 발생하도록 상황을 만듦
• SEH를 실행 -> SEH에서 성공 메시지 띄움
• ... 응용할 수 있는 방법은 많다
44. • 안티 리버싱 3
• 최적화 설정을 없애야 예제를 연습하기 좋음
• 아무 데도 쓰이지 않는 변수에 대한 계산을 컴파일러가 마음대로 없애는 경우가 있음
46. IA-32 Instruction
• instruction
• 쉽게 말해서 CPU가 알아들을 수 있는 기계어(Machine Language)
• IA-32 instruction
• IA-32(IntelArchitecture 32비트) 계열의 CPU에서 사용되는 instruction
• IA-32는 0x86, x86이라고도 함
• CISC(Complex Instruction Set Computer) 이다.
• 명령어 길이가 가변적
• 기계어를 해석하는 방법을 알아보자
• 이유
• 고급 리버싱에서 마주칠 다형성(polymorphic) 엔진을 이해하기 위해
• 다형성 코드 : 코드 자체의 기능은 변하지 않지만 실행 시마다 코드의 내용이 변화되는 것
• 공부하면 배경지식이 됨
47. IA-32 Instruction
• 용어 정리
용어 설명
Machine
Language
기계어, CPU가 해석할 수 있는 Binary 코드
Instruction 하나의 기계 명령어 단위(OpCode와 Operand 등으로 구성됨)
OpCode Operation Code. Instruction 내의 실제 명령어
Assembly 어셈블리 프로그래밍 언어
Assemble 어셈블리 코드를 기계어로 변환하는 작업
Assembler Assemble 작업을 수행하는 프로그램
Disassemble 기계어를 다시 어셈블리어로 변환하는 작업
Disassembler Disassemble 작업을 수행하는 프로그램
Disassembly Disassemble 과정을 거쳐서 생성된 어셈블리 언어 (변수명, 함수명 등은 주소값으로 대체되어 가독성이 떨
어짐)
Compile 고급 언어를 기계어로 변환하는 작업 (Obj 파일 생성)
Link Obj 파일들을 실행 가능한 파일 형태로 연결하는 작업( EXE/DLL 파일 생성)
48. IA-32 Instruction
• Disassembler
• 오른쪽은 익히 보아오던Ollydbg의 화면이다
• Ollydbg에는 IA-32용 Disassembler가 탑재되어 있다
• disassembly 코드는 크게 행위를 결정하는 Mnemonic(니마닉) 부분과 대상을 가리키는Opernad(오퍼랜드) 부분으로 나누
어 진다
• 예) push 2 에서 push부분이 mnemonic이고, 2가 operand이다
49. IA-32 Instruction
• Decompiler
• Disassembler와 같은 개념
• Disassembler는 디스어셈블리 코드로 변환해 주는데 반해, Decompiler는 원본 소스코드 형태(고급 언어)로 변환시켜준다
• 원본 소스코드와 약간의 차이는 있지만, 기술이 발전하며 어느정도 좁혀지고 있음
• IDA의 hexray기능 등 후에 이용할 것
• Protector와 같이 의도적으로 코드를 깨트려 놓고, 실행 중간에 조합해서 사용하는 기법이 들어갔다면 Decompile이 불가능하
거나 오히려 더 복잡하게 보일 수 있다
50. IA-32 Instruction
• IA-32 Instruction 포맷
• IA-32 명령어는 오른쪽과 같이 총 6개의 항목으로 구성
• 이 중 Opcode는 반드시 존재, 나머지는 옵션
• Instruction Prefixes
• 특정 Opcode가 나올 때 사용
• Opcode의 의미를 보조
• 1바이트 크기를 가짐
• Opcode
• 필수 항목
• 실제적인 명령어를 나타냄
• 1~3바이트의 크기를 가짐
• 1바이트가 대부분, 가끔 2바이트, 3바이트 짜리는 일반적으로 거의 접할 일이 없음
• Opcode는 보통 Operand(피연산자)를 가지는 경우가 많음
• Operand의 종류로는 Register, Memory address, Constant(상수)
• Operand를 결정하기 위해 (보조 수단으로) ModR/M과 SIB가 뒤따라 오는 경우가 있음
• ModR/M
• Opcode를 도와서 Operand를 설명
• Operand의 개수, 종류(register, address, constant) 등
• 1바이트의 크기를 가짐
• 비트 단위로 분리되어 사용
51. IA-32 Instruction
• IA-32 Instruction 포맷
• SIB
• Scale-Index-Base
• ModR/M을 보조할 때 사용
• Opcode의 Operand가 Memory Address인 경우 ModR/M과 함께 사용
• 1바이트의 크기를 가짐
• 비트 단위로 분리되어 사용
• Displacement
• Operand가 Memory Address인 경우 사용
• 변위
• 1, 2, 4바이트로 다양한 크기를 가짐
• Immediate
• Operand가 Constant(상수)일 경우에 이용
• 그 상수를 Immediate이라 부름
• 1, 2, 4바이트로 다양한 크기를 가짐
52. IA-32 Instruction
• IA-32 Instruction 해석
• intel에서 제공하는 공식 매뉴얼을 보며 IA-32 instruction을 해석해 보자
• 다운로드 링크는 참고 사이트에
• 문서의A.3 장에 OpCode와 관련된 테이블이 있음 ->여기서부터 시작할 것
53. IA-32 Instruction
• Opcode
• Opcode Map 참고
• Opcode의 의미를 해석하기 위한 표
• 1바이트짜리Opcode의 예이다
• Opcode를 ‘4’와 ‘1’로 쪼갠 후 행과 열로 이용하여 찾는다
• i64는 64비트에서는 사용하지 않는다는 의미
• o64는 오직 64비트 모드에서만 사용된다는 의미
[prefix][Opcode][ModR/M][SIB][Displacement][Immediate]
54. IA-32 Instruction
• Opcode
• 68 명령어를 찾아보면 PUSH Iz 라고 써 있다
• Iz의 의미?
• 앞의 대문자는Address Method를 의미
• I는 Immediate(상수)를 의미
• 뒤의 소문자는Operand type을 의미
• z는 32bit에서 DWORD(32비트) 크기를 의미
• 즉, 68은 4바이트를 push하는 코드임을 의미
• CPU는 뒤의 4바이트 까지 하나의 instruction임을 인지
[prefix][Opcode][ModR/M][SIB][Displacement][Immediate]
55. IA-32 Instruction
• ModR/M
• OpCode를 찾아보면 MOV Ev, Gv 형태임을 알 수 있다
• Ev와 Gv는 Operand의 형식
• 앞의 대문자는Address Method를 의미, 뒤의 소문자는Operand type을 의미
• E는 Register 혹은 Memory address형태가 가능하다는 의미
• G는 Register 형태만 가능하다는 의미
• v는 4바이트를 의미
• Operand 형태가 E 또는 G라면 Opcode 뒤에 반드시 ModR/M이 따라온다
• ->CPU는 뒤의 1바이트 ModR/M필드가 추가로 필요함을 알 수 있음
[prefix][Opcode][ModR/M][SIB][Displacement][Immediate]
57. IA-32 Instruction
• ModR/M
• ModR/M 테이블을 참고하여 기계어를 해석해 보자
• ModR/M 필드는 비트를 쪼개서 사용한다
• 상위 2비트는 Mod, 중간 3비트는 Reg/Opcode, 하위 3비트는 R/M
• C1 = 11000001(2)
• -> 11 000 001
• 앞의 Opcode에서 자료형의 크기도 정해져 있었음
• ->명령어에 따라 ECX냐CX냐 등을 결정
[prefix][Opcode][ModR/M][SIB][Displacement][Immediate]
58. IA-32 Instruction
• Group
• Group 명령문은Opcode를 ModR/M과 조합하여 최대 8가지 형태의 명
령어(Mnemonic)을 가질 수 있는 Opcode들을 뜻 함
• 이렇게Group 명령어를 잘 활용하면 해석이 복잡해지는 대신 Opcode
Map을 확장시키는 효과를 얻을 수 있음
• OpCode를 찾아보면 정확한 명령어(Mnemonic)이 써 있지 않고,
operand의 형태만이 써 있다
• Ev : 4바이트 짜리 레지스터 혹은 메모리
• Ib : 1바이트 짜리 상수
• 회색으로 표시된 부분은 그룹 명령어에 속한다고 써 있다
• 현재까지 나온 정보에 의하면Grp1 Ev, Ib 임을 알 수 있다
[prefix][Opcode][ModR/M][SIB][Displacement][Immediate]
59. IA-32 Instruction
• Group
• 테이블A-6. Opcode Extensions for One- andTwo-byte Opcode by Group
Number를 찾아본다
• ModR/M의 값인 C3를 이용하여 찾는다
• C3 = 11000011(2)
• -> 11 000 011
• 이 중 가운데 Reg/Opcode를 이용
• 그룹 번호는 Opcode에 따라 정해 짐
• 현재까지 나온 정보에 의하면ADD Ev, Ib 임을 알 수 있다
[prefix][Opcode][ModR/M][SIB][Displacement][Immediate]
60. IA-32 Instruction
• Group
• ModR/M 표를 참고하여Operand를 찾는다
• 앞서 Opcode를 찾았을 때, Ev, Ib였다.
• 뒤는 상수이므로, source 는 표에서 결정하지 않음
• C3 = 11000011(2)
• -> 11 000 011
• Ev였던 Destination에 EBX가 들어 감을 알 수 있음
• 현재까지 나온 정보에 의하면ADD EBX, Ib 임을 알 수 있다
[prefix][Opcode][ModR/M][SIB][Displacement][Immediate]
61. IA-32 Instruction
• Group
• 1바이트 크기의 상수가 포함되었으므로 ModR/M뒤 1바이트를 읽는다
• 최종적으로ADD EBX, 12임을 알 수 있다
[prefix][Opcode][ModR/M][SIB][Displacement][Immediate]
62. IA-32 Instruction
• Prefix
• Opcode 앞에 붙어 Opcode의 의미를 보조
• Opcode 표에서 찾는다
• Operand size와 관련된 prefix라는 것을 알 수 있다
• 정확한 역할은 32비트 크기의Operand를 16비트로, 또
는 16비트 Operand를 32비트로 인식하도록 만드는 것
• 현재까지 나온 정보에 의하면Operand의 크기가 바뀜을 알
수 있다
[prefix][Opcode][ModR/M][SIB][Displacement][Immediate]
63. IA-32 Instruction
• Prefix
• Opcode 표에서 다음 바이트를 찾는다
• 현재까지 나온 정보에 의하면Grp1 Ev, Iz 임을 알 수 있다
[prefix][Opcode][ModR/M][SIB][Displacement][Immediate]
64. IA-32 Instruction
• Prefix
• ModR/M을 이용하여 그룹에서의 정보를 찾는다
• FE = 1111 1110
• -> 11 111 110
• 가운데 111을 이용하여 찾는다
• 현재까지 나온 정보에 의하면CMP Ev, Iz 임을 알 수 있다
[prefix][Opcode][ModR/M][SIB][Displacement][Immediate]
65. IA-32 Instruction
• Prefix
• ModR/M을 이용하여 그룹에서의 정보를 찾는다
• CMP Ev, Iz 에서 Ev와 Iz는 둘 다 32비트를 의미한다
• ->Prefix로 인하여 16비트로 바뀜
• FE = 1111 1110
• -> 11 111 110
• Prefix가 없다면CMP ESI, Iz지만 Prefix로 인해 CMP SI, 16비트 상
수 꼴이 됨
[prefix][Opcode][ModR/M][SIB][Displacement][Immediate]
66. IA-32 Instruction
• Prefix
• 16비트(2바이트) 크기의 상수가 포함되었으므로 ModR/M뒤 2바이
트를 읽는다
• 최종적으로CMP SI, 1234 임을 알 수 있다
[prefix][Opcode][ModR/M][SIB][Displacement][Immediate]
67. IA-32 Instruction
• 2바이트 Opcode
• 1바이트 크기의Opcode만으로는 부족하기 때문에 2바
이트로 확장 시킴
• 첫 바이트는 0F로 고정되어 있음
• Opcode Map에서 찾는 방식은 동일
• 두 번째 바이트의 의미를 알아내기 위해A-3 테이블을 참
고한다
• Jcc에 속하고, NE/NZ이다.
• Jcc는 conditional jump를 의미하는 명령어다. cc에
는 번호에 따라 다른 내용이 들어간다
• 즉, JNE/JNZ(이 둘은 같은 일을 한다) 임을 의미한다
• Jcc 옆에 Long-displacement라고 써 있다.
• 4바이트 크기의 displacement로 이용함을 의미
• 현재까지 나온 정보에 의하면 JNZ 임을 알 수 있다
[Prefix][Opcode][ModR/M][SIB][Displacement][Immediate]
68. IA-32 Instruction
• 2바이트 Opcode
• 4바이트 크기의 displacement를 읽는다
• 최종적으로 JNZ 주소 형태임을 알 수 있다
• 기계어에 적힌 주소는 상대주소
• 이 기계어를 실행했을 때 EIP에 더해 줌
[Prefix][Opcode][ModR/M][SIB][Displacement][Immediate]
69. IA-32 Instruction
• Displacement & Immediate
• 주소와 상수가 전부 이용되는 경우를 알아보자
• OpCode를 찾아보니Group 11에 속하며 Ev, Iz를 operand
로 가진다.
• Group 명령어 테이블에서 ModR/M을 이용하여 찾아보
니 MOV Ev, Iz 임을 알아 냈다.
• 05 = 0000 0101(2)
• -> 00 000 101
• 현재까지 나온 정보에 의하면 MOV Ev, Iz 임을 알 수 있다
[Prefix][Opcode][ModR/M][SIB][Displacement][Immediate]
70. IA-32 Instruction
• Displacement & Immediate
• ModR/M을 이용하여 Ev에 어떤 것이 속하는지 알아보자
• 05 = 0000 0101(2)
• -> 00 000 101
• Ev에 속하는 것은 disp32이다.
• Displacement 32비트를 의미
• ->다음 4바이트는 displacement
• 현재까지 나온 정보에 의하면 MOV [4바이트 크기 주소], Iz
임을 알 수 있다
[Prefix][Opcode][ModR/M][SIB][Displacement][Immediate]
71. IA-32 Instruction
• Displacement & Immediate
• 4바이트 크기의 displacement를 읽는다
• 현재까지 나온 정보에 의하면 MOV [40CF00], Iz 임을 알 수
있다
• 그 다음 4바이트 크기의 immediate를 읽는다
• ->MOV [40CF00], 10001 임을 알 수 있다
[Prefix][Opcode][ModR/M][SIB][Displacement][Immediate]
72. IA-32 Instruction
• SIB
• Scala, Index, Base
• Operand가 Memory address를 가리킬 때 사용됨
• Opcode
• Mov Gv, Ev 형태임을 알 수 있다
• G : 레지스터
• E : 레지스터 혹은 메모리 주소
• 현재까지 나온 정보에 의하면 MOV Gv, Ev 임을 알 수 있다
[Prefix][Opcode][ModR/M][SIB][Displacement][Immediate]
73. IA-32 Instruction
• SIB
• ModR/M
• 0C : 0000 1100(2)
• -> 00 001 100
• Mov Gv, Ev 형태이므로
• Gv에 해당하는 레지스터는 ECX
• Ev에 해당하는 값은 [--][--]
• 메시지 주소를 가리키며, 정확한 주소를 표현하기 위
해 SIB가 필요하다는 의미
• 혹은 다음과 같이 직관적으로 표현할 수 있음
• [--][--] = [(Reg.A) + (Reg.B)]
• Reg.A, B 둘 중 하나는 생략 가능함
• 현재까지 나온 정보에 의하면 MOV ECX, [--][--] 임을 알 수
있다
• -> MOV ECX, [(Reg.A) + (Reg.B)]
[Prefix][Opcode][ModR/M][SIB][Displacement][Immediate]
75. IA-32 Instruction
• SIB
• 조금 더 복잡한 형태의 SIB 이용법을 보자
• OpCode를 보아 LEA Gv, M임을 알 수 있다
• M은 오직 메모리 주소를 의미
• 현재까지 나온 정보에 의하면 LEAGv, M임을 알 수 있다
[Prefix][Opcode][ModR/M][SIB][Displacement][Immediate]
76. IA-32 Instruction
• SIB
• ModR/M
• 84 : 1000 0100(2)
• -> 10 000 100
• 앞의 Gv는 EAX
• 뒤의 M은 [--][--]+disp32
• 메모리 주소이며 정확한 해석을 위해 SIB와 Displacement를 읽어야
함
• 조금 더 직관적으로 쓰면
• -> [--][--]+disp32 = [(Reg.A)+(Reg.B)+disp32]
• Reg.A, B 둘 중 하나는 생략 가능
• 현재까지 나온 정보에 의하면 LEA EAX, [--][--]+disp32 임을 알 수 있다
• -> LEA EAX, [(Reg.A)+(Reg.B)+disp32]
[Prefix][Opcode][ModR/M][SIB][Displacement][Immediate]
77. IA-32 Instruction
• SIB
• SIB
• 28 : 0010 1000(2)
• -> 00 101 000
• Reg.A는 EAX, Reg.B는 EBP
• 현재까지 나온 정보에 의하면 LEA EAX, [EAX+EBP+disp32] 임을 알 수 있
다
[Prefix][Opcode][ModR/M][SIB][Displacement][Immediate]
78. IA-32 Instruction
• SIB
• Displacement
• 다음 4바이트를 읽어 구한다
• -> LEA EAX, [EAX+EBP+4035B1]
• EAX에 [EAX+EBP+4035B1] 주소부터 시작하여 4바이트를 옮
기므로 DWORD PTR이 붙었다.
[Prefix][Opcode][ModR/M][SIB][Displacement][Immediate]