YeoPEVA

리버싱 핵심원리 6장, 7장 필기 및 정리 본문

#Reversing/Reversing - 정리

리버싱 핵심원리 6장, 7장 필기 및 정리

YeoPEVA 2018. 2. 22. 20:44


리버싱 핵심원리 6장 및 7장 필기 및 정리 본입니다.

필기 할 때 정신줄 놓은 상태여서 그런지 혼잣말이 많네요 ㅎㅎ..




6. abex’s 크랙미 1 분석 | [코드엔진 문제 1번을 참고해주시면 감사하겠습니다.]

 

crackme -> 크랙 연습을 목적으로한 프로그램

 

[1]프로그램 테스트 및 분석 시작

실행 하고 나서 보며는 메시지 박스 출력이 되는데, 여기서

CD-ROM 인식을 시키게 만들어야함. [관련 API 호출 숙지]

 

소스코드가 매우 짧음.. [어셈블리로 개발 예상]

why?

-> VC++, VC , Delphi 등 개발툴을 사용하게 되면 소스코드 외에 컴파일러가 stub code를 추가,

디스 어셈블시 엄청 복잡해짐 [어쩐지 쓸데 없는거 엄청 많아보인다카더만..]

-> 어셈블리 언어 작성 | 어셈 코드가 곧 디스어셈 코드 | 군더더기 없는 직관적인 코드가 바로 어셈블리

언어로 등#! [어셈블리 언어]


책과 함께 코드 분석 시작


[2] win32 API 중점으로 분석

MessageBox | GetDriveType() API  -> C 드라이브 타입을 얻어옴 [대부분 HDD 리턴]

드라이브 타입 [CD-ROM]이면 클리어! [은근 간단한 것 같기도..]

 

 PUSH – 스택 값 입력 | CALL – 지정된 주소의 함수 호출 | INC, DEC 1 증가, 감소

JMP – 지정된 주소로 점프 | CMP 주어진 두개의 operand 비교 [SUB랑 비슷하나 레지스터만 변경]

값 동일시 SUB 결과는 0, ZF1로 세팅 | JE – 조건 분기 [ZF - 1일시 점프] [ex]



[3]단순 크랙 -> JE short 부분 수정 | GetDriveType 반환 값 수정 해서 크랙  [EAX 리턴값 – 5 수정하면 END]


스택에 파라미터를 전달하는 방법 #

 

메시지박스 함수 호출 전에 4PUSH 명령을 통해 필요한 파라미터를 역순으로 입력하고 있음

-> 스택 메모리 구조 [역순으로 입력해야 올바른 순서로 꺼내는게 가능함]


+ 지식

메시지박스A() 주석 -> ESI 0xFFFFFFFF 세팅 | F8 통한 레지스터 값 확인을 통해 확인 가능

win32 API 호출시, 특정 레지스터 값이 변경되는 경우가 있음 | 주의바람

 

Garbage code -> 디버깅 방해 및 리버서 혼란

+ 외부 영향을 덜 받을 수 있는 조건 분기 명령어를 건들이자.




7. 스택 프레임

 

프로그램에서 선언되는 로컬 변수 및 함수 호출에 사용되는 스택 프레임!에 대해 알아보는 시간이라칸다.

함수 파라미터 및 함수 로컬 변수 등이 쉽게 파악 된다캄 [이해만 한다면요 ㅇㅁㅇ]

 

스택 프레임 – ESP [스택 포인터]가 아닌 EBP 레지스터를 이용하여 스택 내의 로컬 변수 및 파라미터, 복귀주소에

접근하는 기법을 말한다고 함. [ESP – 스택 포인터 / EBP – 베이스 포인터 역할]

 

스택 프레임을 이용해서 함수 호출 관리 -> 스택 완벽 관리 가능

 

PUSH EBP     [함수 시작 [EBP 사용 전, 기존 값 스택 저장]

MOV EBP, ESP [현재의 ESPEBP에다가 저장함]

 

MOV ESP, EBP [ESP 정리 | 함수 시작했을때의 값으로 복원]

POP EBP [리턴 전 저장해 놓았던 원래 EBP 값으로 복원]

RETN [함수 END]

  

+ 최신 컴파일러 최적화 옵션으로 인해, 간단한 함수의 경우 스택 프레임 형성을 안함

+ 스택에 복귀 주소 저장 -> 보안 취약점 [BOF]

 

코드 참고 -> StackFrame.cpp

 

1. PUSH EBP  

-> 값을 스택에 집어 넣는 명령 | EBP 값을 스택에 집어 넣자 | main() 함수에서 EBP가 베이스 포인터 역할

| 이전에 가지고 있던 값을 백업해두기 위해 사용합니다. [나중에 RETN 전에 회복 시킵니다.]

 

2.MOV EBP, ESP

-> MOV를 통해 데이터를 옮김 | ESP 값을 EBP로 옮김 | 스택에 저장된 함수 파라미터 및 로컬 변수들은

EBP를 통해 접근함 | main() 함수에 대한 스택 프레임이 생성됨

 

3. SUB ESP,8

로컬 변수 세팅 | esp 값을 빼주면서 로컬 변수 공간 확보 | long 타입 - 4바이트 [8바이트 크기 공간 필요]

그 후 EBP 값을 통해 -4, -8 이런 식으로 로컬 변수에 엑세스가 가능해진다.

 

MOV DWORD PTR SS:[EBP -4],1    [요로콤 말이죠]

MOV DWORD PTR SS:[EBP -4],2    [요로콤 말이죠!!]

[DWORD PTR ? -> 포인터 개념이라고 생각하면 편함]

[DWORD, WORD, BYTE] PTR SS:[EBP-4]

 

위에서 SS를 같이 표시하는 이유

windows에서 세그먼트 메모리 모델을 사용하기 때문에, 해당 메모리가 어떤 세그먼트에 소속되어 있는지

표시해주는 용도로 쓰임, 실제로는 32비트 win os에서 SS,DS,ES 값은 모두 0..

그래서 큰 의미는 없다만, EBP,ESP는 스택을 가리키는 레지스터들이라 SS 레지스터를 붙여준 것임.

[+ 옵션으로 DWORD PTR SS 등의 문자열을 보이지 않게 하는 것이 가능]

 

그 후

인자 값을 EAX ECX에 넣어주고, 함수를 호출시킨다. [전형적인 함수 호출 과정]

인자 입력 순서 [반대로 입력]

 

그 다음 복귀 주소 저장 [PUSH EBP 저장]   | 반환 값 – EAX 저장 후 리턴


옵션 변경

 

디버깅 옵션에서 Option Dialog [Alt+O]

Disasm 탭에서 show default segments 항목  | Always show size of memory operands

항목 선택해제시 -> 세그먼트 표시 및 메모리 크기 표시가 사라지게 됨

+DWORD PTR이 그래도 있는 경우? -> 크기 해석이 모호할 경우

 

+Analysis1 에서

Show ARGs and LOCALs in procedures 항목 체크하면 EBP 표시되던 함수 로컬 변수와 파라미터가

[LOCAL,1] [ARG,1] 형식으로 바뀜 , 가독성이 높아져 분석이 더욱 쉬워진다 ㅇㅇ