wonder

정보보안 스터디 - 18주차 5일 - PEview, ollydbg 분석 본문

Security/리버싱

정보보안 스터디 - 18주차 5일 - PEview, ollydbg 분석

wonder12 2023. 2. 14. 02:37

 

☞ PEview 분석

 

계산기 PEview보면서 각자의 섹션, 영역을 확인하고

 예를들어 RVA 3000 가 어떤 섹션에 있는지 찾을 수 있기 만하면됩니다.

계산하기 보다는 섹션부분, 패딩부분 주소나 왜 이렇게 되는지 알고 있으면 됩니다.

 

PEview에서는 기계어로 되어있기때문에

분석하기 위해서 ollydbg를 열어 disassembly를 해야합니다. 

 

참고로 pfile=HxD의 offset주소입니다.

 

 

rsrc섹션
아이콘 이미지 등 리소스가 들어있습니다.
reloc섹션
재배치가 포함되어있습니다.
다른 실행파일이 이미 주소를 쓰고 있으니 다른 주소를 찾아서 로드해줍니다.

 

 

 

IAT(Import address table)

이 가장 중요합니다.

암시적이든 명시적링킹이든

각 dll에 대한 함수들이 나오고

함수 호출 주소값을 찾을 수 있습니다.

 

SHELL32.dll 첫번째 함수의 RAW 구하기 및 함수 이름 확인을 계산할 줄 알아야합니다.

 

 

prebinding

링킹할 때 IAT에 실제 import 하는 함수의 주소를 미리 구성하는 기능입니다.

미리완성시켜 시간단축시키기 위함입니다. 

즉 PEview에서 IAT에 기록된 함수 주소와

olly에서 확인한 실제 메모리 상의 주소가 다릅니다.

 

 

 

 

 

 HxD Compare 코드 비교

 

결국 목적은

기존에 소스코드가 밝혀지지 않은 프로그램들이 많기 때문에

기계어로 접근해서 어셈블리어로 만들고 분석하는 겁니다.

 

결국 악성코드 분석 하거나 프로그램에 잘못된 점이 있으면 HxD hex 에디터로 offset 주소로 가서 고쳐줍니다.

비교를 할 수도 있습니다. analysis > compare 로 들어가서 파일을 비교해주면

마우스를 동일한 위치로 놓고 F6으로 누르면 비교하면서 다른부분이 있다면 검사해서 멈춰줍니다.

하나씩 멈춰서 비교할 수 있습니다.

빠진 부분이라던지 살작 달라진 부분이 있으면 실행될 수도 있지만 오류가 생겨서 안될 경우도 많습니다.

 

나중에는 작동하는 방식을 알고

아 프로그램이 이렇게 작동하고 있구나. 이렇게 구성되어 있구나

하고 프로그램을 직접 만들거나, 편집할 수 있습니다.

이렇게 봤을 때, 리버싱 분석은 중요한 기술입니다.

 

 

 

 

 

 명시(함수) VS 암시(목록)

dll을 직접적으로 가져온다면 암시적 링킹이고
(PEVIEW의 에서 user32.dll이있고 load, getaddress함수가 없는 것을 확인가능합니다.)

load로 dll파일을 불러오고 getaddress 로 그중에서 lockworkstation함수를 불러오는 것이 명시적 링킹입니다.

참고로 dll도 PE파일입니다.


파일에 dll파일이 뭐가 있는지 구성을 확인하려면
dependency walker 가 보기 좋습니다.

 

 

 

 

 

 소스코드 제작 후 exe파일 생성

생성은 

보통 프로그램을 만들려면

옛날버전이긴 하지만 visual C++ 에서 빈프로젝트 새로 만들기 > C언어 소스 코드 작성 > 디버그 debug, 배포용 release 실시(컴파일 까지 합니다.)  > 모두 저장 > exe파일 생성 확인

또는 잡다한 코드 없이 제작하여 분석하기 위해서 모두 저장 후에 >  shift+우클릭 명령창열기 > cl  > 컴파일 할 수 있습니다. 

.cpp 파일이 제작이 먼저되고 후에 exe가 생성됩니다.

 

 

 exe파일 생성 예시 1)

 

VS 2008 C++ 을 실행하여

빈 프로젝트 새로만들기

C++ 파일(.cpp)을 새로 만들어 해당 소스 코드를 넣습니다. (static linking 함수 코드직접넣는 방식)

#include <stdio.h>
int main()
{
	int num1 = 6;
	int num2 = 2;
	return 0;
}

모두 저장 후

cpp폴더 > 여기서 명령어 창 열기 >

cl lv.cpp /link /debug /opt:icf,ref

exe파일을 생성합니다.

 

 

 

 

함수 호출 이전

메인 함수가 호출 CALL되기 전에

3개의 인자값들이 스택에 PUSH됩니다. 

그다음 RET리턴주소를 저장한 다음 함수가 시작됩니다.

함수가 들어갈 경우: 함수 처리가 완료되면 결과값(리턴값)을 EAX 레지스터에 저장해서 리턴하고 함수를 종료합니다.

(스택창에 보면 함수가 종료됐을 대 돌아갈 리턴 주소가 저장됨과 옆에 설명을 볼 수 있습니다.)

 

 

PUSH env
PUSH argv
PUSH argc

구조로 되어있고

그다음 메인함수 CALL을 합니다.

F7로 넘어가서 안에 내용을 모두 실행 후 다시 ret 주소로 돌아옵니다.

 

 

 

프롤로그 

 

PUSH EBP
처음에는 스택에 EBP를 PUSH하고
MOV EBP, ESP
ESP 값을 EBP에 대입하여 main함수의 기준점을 잡습니다.

여기까지가 프롤로그입니다.

 

 

지역 변수(int) 선언을 위한 스택 공간 확보

SUB ESP, 8
ESP-8 만큼 ESP의 주소 공간을 확보합니다. (int 2개)

 

 

MOV DWORD PTR SS:[EBP-8], 6
MOV DWORD PTR SS:[EBP-4], 2
지역변수에 각각 6, 2를 대입합니다.

여기서 SS는 지역변수고 DS라면 전역 변수입니다.

 

XOR EAX, EAX
EAX를 0으로 초기화 하여 리턴값으로 사용합니다. = return 0

 

 

 

에필로그에 

MOV ESP, EBP
EBP값을 ESP에 대입하여 원상태로 복구하고
POP EBP
POP 으로 기준점 EBP를 제거합니다.
RETN
원래의 주소의 다음 명령어로 점프합니다.

 

 

 

 

  ADD 예시 2) 

 

#include <stdio.h>
int main()
{
	int num1 = 6;
	int num2 = 2;
	int num3;
    
	num3 = num1 + num2;
	return 0;
}

 

프롤로그

PUSH EBP
EBP를 스택에 PUSH
MOV EBP,ESP
ESP로 기준점 잡기

 

 

메인

SUB ESP, 0C
변수 선언을 위한 스택 공간 확보(int 자료형 3개)
MOV DWORD PTR SS:[EBP-C],6
6을 ebp-c에 대입. 여기서 EBP-C는 int num1을 의미합니다.
MOV DWORD PTR SS:[EBP-8],2
2을 ebp-8에 대입. 여기서 EBP-8는 int num2을 의미합니다.
MOV EAX, DWORD PTR SS:[EBP-C]
EBP-C값 6을 EAX에 대입합니다.
ADD EAX, DWORD PTR SS:[EBP-8]
6과 2를 더하고 값을 EAX에 저장합니다.
MOV DWORD PTR SS:[EBP-4], EAX
EAX 값 8을 EBP-4에 대입합니다. 여기서 EBP-4는 int num3을 의미합니다.
XOR EAX, EAX
EAX를 0으로 초기화하여 리턴값으로 사용합니다.

 

 

에필로그

MOV ESP, EBP
EBP를 ESP로 대입하여 원래 상태로 복구합니다.
POP EBP
EBP기준을 제거합니다.
RETN
다음 명령 주소로 돌아갑니다.

 

 

ollydbg 확인법

home을 눌러 main함수를 확인하고

F2 breakpoint를 걸고 실행해서

call 함수호출하는 주소로 F7을 눌러 들어가서 

F8로 단계별로 하나하나씩 실행하면서 어떻게 작동하는지 확인합니다.

EBP, ESP, 스택 구성 등을 보면서 변화를 확인합니다.

 

다시 RET으로 돌아갑니다.

 

 

 

 

 

  레지스터 종류(메인 8개)

 

32비트면 E 로 시작합니다.

EAX 
산술 연산, 주로 결과값
리턴값이 저장되며 성공/실패 여부를 알 수 있습니다.
EDX
마찬가지로 산술연산이며,
32비트를 넘을 시 추가 저장공간
나머지 값 저장
ECX
반복, 카운터값
EBX
여분의 레지스터
ESI, > EDI
source에서 destination으로 데이터 복사됩니다.
ESP 
스택의 위치
EBP
함수의 기준점
ESI
다음 실행할 명령어의 주소를 저장합니다.
리턴 주소값으로 저장시키므로 은근 중요합니다. 

위의 내용은 절대적인 것은 아닙니다.

 

 

레지스터는 총 9개로 구성되고

레지스터 창에서 확인할 수 있습니다.

메모리주소/프로그램코드창/ 레지스터창
메모리창 / 스택 구성(address> relative to EBP)

 

 

 

  명령어 종류

MOV
source 값을 복사하는 대입 명령어입니다.

윈도우는 리눅스와 반대로
< 방향으로 대입(복사)합니다.
MOVZX
빈공간을 0비트(0)으로 채웁니다.
MOVSX
대입 후 빈공간이 있으면 부호비트로 채웁니다.
MOVS
ESI가 가르키는 주소의 값을 EDI가 가르키는 주소에 대입합니다.

esi 0x10
edi 0x20

0x10 A
0x20 A

 

LEA operand 1, 2
MOV가 값을 복사했다면 이건 주소를 대입합니다.

0x2000  ebp-4  a
mov 면  a
lea면 2000
ADD operand 1, 2
1, 2를 더하고 결과값을 1에 저장합니다.

EBP기준점으로 쓴다면 스택 공간을 삭제하는 동작으로도 쓰입니다.
SUB operand 1, 2
빼서 값을 1에 저장합니다.
CDQ 
나누기에서 사용됩니다.
증감문 INC, DEC
증감 반복문 있을 때 자주사용됩니다.
CMP operand 1, 2
비교합니다.
리턴값이 0이라면 같은 값입니다.
TEST EAX, EAX
이것도 비교문입니다.
AND연산으로
0 AND 0 두 EAX가 모두 0이맞다면 참이 뜨므로
참/거짓을 알 수 있습니다.






  상태 플래그

ZF zeroflag 0이면 zf=1
SF  음수면 sf=1
CF 부호가 없는 숫자의 연사결과가 비트 범위를 넘으면 1로 설정
OF

Z, S만 잘보면 됩니다.

 

 

 

 

  바이트 오더링
데이터를 메모리에 저장할 때 1 bytes씩 저장하는 방식입니다.

 

 

  엔디언 방식

 

빅 엔디언

순서대로 읽기

 

리틀 엔디언

반대로 읽기

intel계열 CPU에서 사용=대부분이라고 보면됩니다.

 

 

얘를들어 

WORD나 DWORD 자료형은  12 34 56 78 > 78 56 34 12
단 char 문자열은 한바이트씩 그대로 읽습니다. 61 62 63 64 65

 

 

 

 

 

 

Comments