메시지 처리 함수란 메시지가 발생할 때 프로그램의 반응을 처리하는 일을 하며 WinMain 함수와는 별도로 WndProc(Window Procedure)이라는 이름으로 존재한다. 

 

WinMain 내의 메시지 루프는 메시지를 메시지 처리 함수로 보내주기만 할 뿐이며 WndProc은 메시지가 입력되면 윈도우즈에 의해 호출되어 메시지를 처리한다. 이렇게 운영체제에 의해 호출되는 응용 프로그램 내의 함수콜백(Callback)함수라고 한다.

 

WndProc의 인수는 모두 4개이며 이전 글에서 봤던 MSG 구조체의 멤버 4개와 동일하다.

typedef struct tagMSG
{
    HWND        hwnd;
    UINT        message;
    WPARAM      wParam;
    LPARAM      lParam;
    DWORD       time;
    POINT       pt;
} MSG;

<WndProc>

hWnd : 메시지를 받을 윈도우의 핸들

iMessage : 어떤 변화가 발생했는가에 관한 정보. (메시지 변수)

wParam, IParam : iMessage에 따른 부가적인 정보 (어디쯤에서 마우스 버튼이 눌렸는가, 어떤 문자열이 입력됐는가,,)

 

WndProc의 구조는 아래와 같다. 메시지의 종류에 따라 다중 분기하여 메시지별로 처리를 진행한다.

switch(iMessage)
{
	case Msg1:
		처리1;
		return 0;
	case Msg2:
		처리2;
		return 0;
	case Msg3:
		처리3;
		return 0;
	default:
		return DefWindowProc(...);
}

마지막에 DefWindowProc 함수는 WndProc에서 처리하지 않은 나머지 메시지에 관한 처리를 해 준다.

 

이전 글의 코드에서의 메시지 처리 함수는 아래와 같이 되어 있다.

LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
	switch(iMessage) {
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}

여기서는 WM_DESTROY 메시지만을 처리하고 있으며 나머지 메시지에 대해서는 DefWindowProc에게 맡긴다.

WM_DESTROY 외의 메시지는 모든 DefWindowProc 함수로 전달되며 이 함수에서 디폴트 처리를 수행해 준다. 

WndProc은 메시지를 처리했을 경우 반드시 0을 리턴해 주어야 한다.

또한 DefWindowProc 함수가 메시지를 처리했을 경우 이 함수가 리턴한 값을 WndProc 함수가 다시 리턴해 주어야 한다. 

 

 

'Project > WIN32 API' 카테고리의 다른 글

그래픽 오브젝트  (0) 2021.07.12
그래픽  (0) 2021.07.08
리소스  (0) 2021.07.07
윈도우 창 생성 과정  (0) 2021.06.25
윈도우즈 프로그래밍  (0) 2021.06.25

 

#include <windows.h>

LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
HINSTANCE g_hInst;
LPSTR lpszClass="First";

int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance
		  ,LPSTR lpszCmdParam,int nCmdShow)
{
	HWND hWnd;
	MSG Message;
	WNDCLASS WndClass;
	g_hInst=hInstance;
	
	WndClass.cbClsExtra=0;
	WndClass.cbWndExtra=0;
	WndClass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
	WndClass.hCursor=LoadCursor(NULL,IDC_ARROW);
	WndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
	WndClass.hInstance=hInstance;
	WndClass.lpfnWndProc=(WNDPROC)WndProc;
	WndClass.lpszClassName=lpszClass;
	WndClass.lpszMenuName=NULL;
	WndClass.style=CS_HREDRAW | CS_VREDRAW;
	RegisterClass(&WndClass);

	hWnd=CreateWindow(lpszClass,lpszClass,WS_OVERLAPPEDWINDOW,
		  CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
		  NULL,(HMENU)NULL,hInstance,NULL);
	ShowWindow(hWnd,nCmdShow);
	
	while(GetMessage(&Message,0,0,0)) {
		TranslateMessage(&Message);
		DispatchMessage(&Message);
	}
	return Message.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
	switch(iMessage) {
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}

실행 결과, 간단한 윈도우 창이 보인다.

 

1. 헤더 파일

첫 행을 보면 windows.h 하나만 include 되어있다.

여기에 모든 API 함수들의 원형과 사용하는 상수들이 죄다 정의되어 있다.

 

2. 시작점

int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance ,LPSTR lpszCmdParam,int nCmdShow)

프로그램의 시작점인 엔트리 포인트(Entry Point)가 WinMain이다.

DOS의 main에서는 인수 사용여부에 따라 여러가지 원형이 있지만 WinMain의 원형은 고정되어 있다.

4개의 인수를 취하는데, 각 인수의 의미는 다음과 같다.

 

인수 의미
hInstance 프로그램의 인스턴스 핸들. 프로그램 자체를 일컫는 정수값
hPrevInstance 바로 앞에 실행된 현재 프로그램의 인스턴스 핸들
없을 경우에는 NULL이며 Win32에서는 항상 NULL
호환성을 위해 존재하는 인수이므로 신경쓰지 않아도 됨
IpCmdLine 명령행으로 입력된 프로그램 인수. DOS의 argv인수에 해당
nCmdShow 프로그램이 실행될 형태이며 최소화, 보통모양 등이 전달됨

 

인스턴스(instance)

:: 클래스가 메모리에 실제로 구현된 실체

HINSTANCE g_hInst;

윈도우즈 프로그램은 여러 개의 프로그램이 동시에 실행되는 멀티태스킹 시스템이며 하나의 프로그램이 여러 번 실행될 수 도 있다. 이때 실행되고 있는 각각의 프로그램을 프로그램 인스턴스라고 하며 간단히 줄여서 인스턴스 라고 한다.

 

예를 들어, 메모장 프로그램 창이 2개 띄어진 상황이라고 생각해보자.

두 프로그램 모두 메모장(Notepad.exe)이지만 운영체제는 각각 다른 메모리를 사용하는 다른 프로그램으로 인식한다.

이때 각 메모장은 서로 다른 인스턴스 핸들을 가지며, 운영체제는 이 인스턴스 핸들값으로 두 개의 메모장을 서로 구별한다.

 

 

3. 메시지 처리 함수

코드를 자세히 보면 두 개의 함수만 있다.

하나는 프로그램의 시작점인 WinMain이고 나머지 하나는 WndProc이다.

DOS에서는 main 함수만으로도 프로그램을 작성할 수 있지만 윈도우즈에서는 아주 특별한 경우를 제외하고는 이 두개의 함수가 모두 있어야 한다.

 

: WinMain에서는 윈도우를 만들고 화면에 출력하는 일만 한다. 그저 프로그램을 시작시키기만

: WndProc이 실질적인 처리를 한다.  이는 프로그램에 따라 천차만별로 달라지며 보통 WinMain 바로 윗부분에 WndProc 함수의 원형이 선언되어 있다.

LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);

 

 

4. 윈도우 클래스

WinMain 함수에서 하는 가장 중요한 일은 윈도우를 만드는 일이다.

이를 위해선 윈도우 클래스를 먼저 등록한 후 CreateWindow 함수를 호출해야 한다.

윈도우 클래스는 windows.h에 아래와 같이 정의되어 있다.

typedef struct tagWNDCLASS
{
    UINT        style;
    WNDPROC     lpfnWndProc;
    int         cbClsExtra;
    int         cbWndExtra;
    HINSTANCE   hInstance;
    HICON       hIcon;
    HCURSOR     hCursor;
    HBRUSH      hbrBackground;
    LPCSTR      lpszMenuName;
    LPCSTR      lpszClassName;
} WNDCLASS;

10개의 멤버를 가지고 있는데 각각 간단하게 설명하면 아래와 같다.

- style : 윈도우의 스타일

- lpfnWndProc : 윈도우 메시지 처리 함수 지정

- cbClsExtra, cbCWndExtra : 예약 영역, 여분의 공간

- hInstance : 이 윈도우 클래스를 사용하는 프로그램의 번호

- hIcon, hCursor : 이 윈도우가 사용할 마우스 커서와 최소화되었을 경우 출력될 아이콘 지정

- hbrBackground : 윈도우의 배경 색상

- lpszMenuName : 이 프로그램이 사용할 메뉴를 지정

- lpszClassName : 윈도우 클래스의 이름을 정의

 

 

ATOM RegisterClass( CONST WNDCLASS *lpWndClass);

RegisterClass 함수의 인수로 WndClass 구조체의 주소를 넘겨주면 된다.

	WNDCLASS WndClass;
	
	WndClass.cbClsExtra=0;
	WndClass.cbWndExtra=0;
	WndClass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
	WndClass.hCursor=LoadCursor(NULL,IDC_ARROW);
	WndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
	WndClass.hInstance=hInstance;
	WndClass.lpfnWndProc=(WNDPROC)WndProc;
	WndClass.lpszClassName=lpszClass;
	WndClass.lpszMenuName=NULL;
	WndClass.style=CS_HREDRAW | CS_VREDRAW;
	RegisterClass(&WndClass);

이런 특성을 가진 윈도우를 앞으로 사용하겠다는 등록 과정인 셈이다.

 

윈도우 클래스를 등록한 후에는 등록한 윈도우 클래스를 기본으로 윈도우를 실제로 생성해야 한다. 

윈도우를 생성할 땐 CreateWindow 함수를 사용한다.

 

HWND CreateWindow(lpszClassName, lpszWindowName, dwStyle, x, y, nWidth, nHeight, hwndParent, hmenu, hinst, lpvParam)

11개의 인수를 가지고 있는데 각각 간단하게 설명하면 아래와 같다.

- lpszWindowName : 윈도우의 타이틀 바에 나타날 문자열

- dwStyle : 만들고자 하는 윈도우의 형태를 지정(시스템 메뉴, 최대 최소 버튼, 타이틀 바, 경계선 등)

- X, Y, nWidth, nHeight : 윈도우의 크기와 위치 지정. 픽셀 단위

- hWndParent : 부모 윈도우 있을 경우, 부모 윈도우의 핸들을 지정

- hmenu : 윈도우에서 사용할 메뉴의 핸들을 지정

- hinst : 윈도우를 만드는 주체, 즉 프로그램의 핸들을 지정

- lpvParam : CREATESTRUCTURE라는 구조체의 주소이며 특수한 목적에 사용. 보통 NULL 값

 

CreateWindow 함수는 윈도우에 관한 모든 정보를 메모리에 만든 후 윈도우 핸들을 리턴값으로 넘겨준다.

넘겨지는 윈도우 핸들은 hWnd라는 지역 변수에 저장되어 다른 곳에서 참조된다.

 

 

BOOL ShowWindow(hWnd, nCmdShow);

메모리에 저장되어진 윈도우를 화면으로 보이게 할 때 쓰이는 함수이다.

hWnd 인수는 화면으로 출력하고자 하는 윈도우의 핸들이며 CreateWindow 함수가 리턴한 핸들을 그대로 넘겨주면 된다.

 

 

각각의 자세한 의미를 파악하려면 아래의 링크를 참고하자

http://soen.kr/lecture/win32api/ApiLec.htm

 

API 강좌

 

soen.kr

 

 

윈도우를 만드는 과정을 간단하게 정리하면 아래와 같다.

 

WndClass 정의  : 윈도우의 기반이 되는 클래스 정의

CreateWindow : 메모리 상에 윈도우 생성

ShowWindow : 윈도우를 화면에 표시

메시지 루프 : 사용자로부터의 메시지를 처리

 

 

5. 메시지 루프

 여기서 메시지란 사용자나 시스템 내부적인 동작에 의해 발생된 일체의 변화에 대한 정보를 말한다.

쉽게 말해서 사용자가 마우스의 버튼을 눌렀다거나 키보드를 눌렀다거나 윈도우가 최소화되었거나 하는 정보들이 메시지이다.

 

메시지가 발생하면 프로그램에서는 메시지가 어떤 정보를 담고 있는가를 분석하여 어떤 루틴을 호출할 것인가를 결정한다. 

즉, 순서를 따르지 않고 주어진 메시지에 대한 반응을 정의하는 방식으로 프로그램이 진행된다는 뜻

 

보통 WinMain 함수의 끝에 아래와 같은 형식으로 존재한다.

	while (GetMessage(&Message,NULL,0,0)) {
		TranslateMessage(&Message);
		DispatchMessage(&Message);
	}

메시지 루프는 세 개의 함수 호출로 이루어져 있으며 전체 루프는 while 문으로 싸여져 있다.

 

(1) BOOL GetMessage( LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax);

 이 함수는 시스템이 유지하는 메시지 큐에서 메시지를 읽어들인다.

읽어들인 메시지는 첫 번째 인수가 지정하는 MSG 구조체에 저장된다. 이 함수는 읽어들인 메시지가 프로그램을 종료하라는 WM_QUIT일 경우 False를 리턴하며 그 외에는 모두 True를 리턴한다. 

따라서 프로그램이 종료할 때까지 while 루프가 계속 실행된다. 나머지 인수는 일단 무시하도록 하자

 

(2) BOOL TranslateMessage( CONST MSG *lpMsg);

 이 함수는 키보드 입력 메시지를 가공하여 프로그램에서 쉽게 쓸 수 있도록 해준다.

즉, 키보드의 눌림(WM_KEYDOWN)과 떨어짐(WM_KEYUP)이 연속적으로 발생할 때 문자가 입력되었다는 메시지(WM_CHAR)를 만드는 역할을 한다. 

 

(3) LONG DispatchMessage( CONST MSG *lpmsg);

 이 함수는 시스템 메시지 큐에서 꺼낸 메시지를 프로그램의 메시지 처리 함수(WndProc)로 전달한다. 

이 함수에 의해 메시지가 프로그램으로 전달되며 프로그램에서는 전달된 메시지를 점검하여 다음 동작을 결정하게 된다.

 

결국, 메시지 루프가 하는 일이란 메시지 큐에서 메시지를 꺼내 메시지 처리 함수(WndProc)으로 보내주는 것 뿐이다.

 

--> 실제 메시지 처리는 별도의 메시지 처리 함수(WndProc)에서 수행한다. 메시지는 시스템의 변화에 대한 정보이며 MSG라는 구조체에 보관된다. 

typedef struct tagMSG
{
    HWND        hwnd;
    UINT        message;
    WPARAM      wParam;
    LPARAM      lParam;
    DWORD       time;
    POINT       pt;
} MSG;
멤버 의미
hwnd 메시지를 받을 윈도우 핸들
message 어떤 종류의 메시지인지. 제일 중요
wParam 전달된 메시지에 대한 부가적 정보. 32비트 값
IParam 전달된 메시지에 대한 부가적 정보. 32비트 값
time 메시지가 발생한 시간
pt 메시지가 발생했을 때의 마우스 위치

 message 멤버를 읽음으로써 메시지의 종류를 파악하며 message 값에 따라 프로그램의 반응이 달라진다.

GetMessage 함수는 읽은 메시지를 MSG 형 구조체에 대입해주며 이 구조체는 DispatchMessage 함수에 의해 응용 프로그램의 메시지 처리 함수(WndProc)으로 전달된다.

 

※ 가장 자주 사용되는 메시지 종류

메시지 의미
WM_QUIT 프로그램 종료 시 발생하는 메시지
WM_LBUTTONDOWN 마우스의 좌측 버튼을 누를 경우 발생
WM_CHAR 키보드로부터 문자가 입력될 때 발생
WM_PAINT 화면을 다시 그려야 할 필요가 있을 때 발생
WM_DESTROY 윈도우가 메모리에서 파괴될 때 발생
WM_CREATE 윈도우가 처음 만들어질 때 발생

 

'Project > WIN32 API' 카테고리의 다른 글

그래픽 오브젝트  (0) 2021.07.12
그래픽  (0) 2021.07.08
리소스  (0) 2021.07.07
WndProc  (0) 2021.06.26
윈도우즈 프로그래밍  (0) 2021.06.25

윈도우즈(Windows)

:: 미국의 마이크로소프트(Microsoft)사에서 만들었으며 83년 11월에 개발 시작, 85년 11월에 첫 버전 발표

:: 이미 시장을 장악하고 있었던 MS-DOS에 비해 멀티 태스킹이 가능

:: 훨씬 더 사용하기 쉽고 예쁜 모양의 GUI 기반 운영체제

:: 장치에 영향 받지 않음

:: 인터페이스 구성이 표준화되어 있어 어떤 프로그램이나 유사한 방법으로 사용할 수 있음

:: 리소스(프로그램에서 필요로 하는 여러가지 데이터)가 분리되어 있음

 

 

API(Application Programming Interface)

:: 운영체제가 응용 프로그램을 위해 제공하는 함수의 집합

 

▷ 운영체제 : 하드웨어와 응용 프로그램 사이에 위치하며 응용 프로그램을 대신하여 하드웨어를 관리하고 메모리를 관리하는 시스템 소프트웨어.

따라서 특정 운영체제에서 실행되는 응용 프로그램은 운영체제에 종속적이며 운영체제가 규정한 바대로 하드웨어를 액세스해야한다.

 

그러나, 응용 프로그램 개발자들이 이러한 운영체제의 내부 동작을 하나하나 이해할 수 없다. 

따라서 운영체제는 가장 기본적인 동작을 할 수 있는 함수의 집합을 응용 프로그램에게 제공할 의무를 지며 응용 프로그램 개발자들은 운영체제가 제공하는 함수들을 사용할 권리와 의무를 가진다.

 

API와 비슷한 말로 SDK 라는 표현이 사용되기도 한다. SDK는 원래 API를 사용하여 프로그램을 개발하는 개발 툴 킷이었으나 지금은 의미가 전용되어 API와 거의 같은 뜻으로 쓰인다. 

 

 

변수 명명법 in 윈도우즈 프로그래밍

윈도우즈에서는 대체로 변수 이름을 길게 쓰며 되도록 보기 좋게(=읽기 쉽게) 하기 위해 대문자와 소문자를 적당히 혼합하여 사용한다. 따라서 외워두면 편리한 접두어들을 소개한다.

접두어 원래말 의미
cb Count of Bytes 바이트 수
dw double word 부호없는 long형 정수
h handle 윈도우, 비트맵, 파일 등의 핸들
sz NULL Terminated NULL 종료 문자열
w Word 부호없는 정수형
i Integer 정수형
Bool  논리형

ex) sbString = 문자열의 바이트 수를 나타내는 정수형 인수(또는 변수)

szMessage = NULL 문자열을 가리키는 포인터

 

 

데이터형

이 데이터형은 windows.h라는 헤더 파일에서 typedef로 선언되어 있다. 거의 모든 프로그램에서 마치 표준 데이터형처럼 사용하므로 알아두면 유용하다.

데이터형 의미
BYTE unsigned char 형
WORD unsigned short 형
DWORD unsigned long 형
LONG long
LPSTR char *
BOOL 정수형, TRUE or FALSE 중 하나

 

 

 

핸들(Handle)

1) 구체적인 어떤 대상에 붙여진 번호, "32비트의 정수값" - 구분을 위한 것이므로 중복되어서는 안됨

2) 운영체제가 발급해 주는 것, 사용자는 쓰기만 하면 됨

3) 핸들은 중복된 값을 가지지 않음

4) 핸들의 실제값을 알 필요가 없음 - 핸들형 변수를 만들어 핸들을 대입받아 쓰고 난 후 버리면 됨

 

핸들은 예외없이 접두어 h로 시작되며 핸들값을 저장하기 위해 별도의 데이터형도 정의되어 있다.

(HWND, HPEN, HBRUSH, HDC 등)

 

 

 

'Project > WIN32 API' 카테고리의 다른 글

그래픽 오브젝트  (0) 2021.07.12
그래픽  (0) 2021.07.08
리소스  (0) 2021.07.07
WndProc  (0) 2021.06.26
윈도우 창 생성 과정  (0) 2021.06.25

Azure에서 제공하는 클라우드 서비스(Portal을 통해 접속)를 이용해 2대의 웹 서버 가상머신을 구축하여 웹 서비스를 진행한다.
이 서비스는 1대의 데이터베이스 서버에 연동되어 있다. 
데이터베이스 서버는 웹 서버와 다른 Region에 존재하며 VPN으로 연동되어 있다.
웹 서버 중 1대만 공인 IP를 기반으로 한 SSH 접속이 가능하며 다른 한 대는 SSH 연결이 NSG로 차단되어 있다.

 

https://azure.microsoft.com/ko-kr/

 

클라우드 컴퓨팅 서비스 | Microsoft Azure

Microsoft Azure의 유연한 개방형 클라우드 컴퓨팅 플랫폼을 통해 목적에 따라 투자하고 비용을 절감하며 조직을 더 효율적으로 만드세요.

azure.microsoft.com


<기본 구성 설정>

[그림 1] Virtual Machine(VM) 3개를 추가한다

 

[그림 2] 첫 번째 Virtual Machine

 

이름 : vm1-eastus-swucloudhw

리소스 그룹 : rg-swucloudhw

공인 IP :  40.117.128.66

Region : 미국 동부

가상 네트워크  : vnet-eastus-swucloudhw

서브넷 : snet01-vnet-eastus-swucloudhw

 

 

[그림 3] 두 번째 Virtual Machine

 

이름 : vm2-eastus-swucloudhw

리소스 그룹 : rg-swucloudhw

공인 IP :  52.149.217.157

Region : 미국 동부

가상 네트워크  : vnet-eastus-swucloudhw

서브넷 : snet02-vnet-eastus-swucloudhw

 

 

[그림 4] 세 번째 Virtual Machine (for DB Server)

 

이름 : vm3forDB-eastaust-swucloudhw

리소스 그룹 : rg-swucloudhw

공인 IP :  40.126.237.187

Region : 오스트레일리아 동부

가상 네트워크  : vnet-eastaust-swucloudhw

서브넷 : snet01-vnet-eastaust-swucloudhw

 

 

[그림 5] 세 번째 Virtual Machine (for DB Server)

 

사설 IP :  172.0.3.4

 


[그림 6] 가상 네트워크 게이트웨이 추가

서로 다른 Region (미국 동부와 오스트레일리아 동부)을 VPN으로 연결해주기 위해서 VGW를 추가한다.

 

 

[그림 7] 첫 번째 Virtual Gateway

 

이름 : vgw01-eastus-swucloudhw

리소스 그룹 : rg-swucloudhw

위치 : 미국 동부

공인 IP : 52.152.142.189

가상 네트워크  : vnet-eastus-swucloudhw

 

 

[그림 8] 두 번째 Virtual Gateway

 

이름 : vgw02-eastaust-swucloudhw

리소스 그룹 : rg-swucloudhw

위치 : 오스트레일리아 동부

공인 IP : 13.75.230.233

가상 네트워크 : vnet-eastaust-swucloudhw

 

 

[그림 9] VPN 구축을 위한 VGW끼리의 connect 설정

VPN(Virtual Private Network) 구축을 위해서 서로 다른 Region에 위치한 VGW(Virtual Gateway)를 서로 연결 시켜주었다.

 

[그림 10] 연결 상세 정보

VPN 구축을 위해 연결된 가상 네트워크의 상세 정보이다.

vnet-eastaust-swucloudhw, vnet-eastus-swucloudhw 끼리 잘 연결된 것을 확인할 수 있다.

 


[그림 11] vnet-eastus-swucloudhw 가상 네트워크 구성 상세 확인

미국 동부에 위치한 vnet-eastus-swucloudhw 의 주소 공간은 10.0.0.0/16 이며 이 가상네트워크에 속한 디바이스들을 확인할 수 있다.

 

[그림 12] vnet-eastaust-swucloudhw 가상 네트워크 구성 상세 확인

오스트레일리아 동부에 위치한 vnet-eastaust-swucloudhw 의 주소 공간은 172.0.0.0/16 이며 이 가상네트워크에 속한 디바이스들을 확인할 수 있다.

 


<DB 서버 설정>

[그림 13] vm3-forDB-eastaust-swucloudhw 에 접속

DB 서버를 위한 가상머신에 접속한 후 sudo apt install mysql-server 명령어를 통해 mysql server를 설치한다.

 

 

[그림 14] mysql 설치 완료한 후 mysql 실행

sudo /usr/bin/mysql -u -root -p 비밀번호 명령어를 입력하여 MYSQL을 실행한다.

 

 

[그림 15] MySQL 버전 확인

show variables like "%version%" 명령어를 통하여 MySQL의 버전을 확인했다.

 

 

[그림 16] 데이터베이스 목록 확인 후 데이터베이스, 테이블 생성

show databases 명령어로 현재 데이터베이스 목록을 확인했고, hw_for_cloud라는 이름의 데이터베이스를 생성했다.

그리고 vm1에 연결할 response1 테이블vm2에 연결할 response2 테이블을 생성했다.
각각은 id, firstname, lastname, email, submitdate 컬럼으로 구성되어 있다.

 

 

[그림 17] 생성 테이블 확인

show tables 명령어로 테이블이 문제 없이 생성된 것을 확인했다.

 

 

[그림 18] response1 테이블에 데이터 추가

response1 테이블에 레코드를 추가(insert)한다. 

lastname이 Lee 인 점을 기억한다.

 

 

[그림 19] response2 테이블에 데이터 추가

response2 테이블에 레코드를 추가(insert)한다.

lastname이 Kim 인 점을 기억한다.

 

 

[그림 20] MySQL 의 root 계정 관련 설정

처음 MySQL을 설치하면 root 계정을 통해 들어갈 때 비밀번호 검사를 하지 않는다.

이는 나중에 외부에서 DB로 연결할 때 root 계정을 인식하는데 문제가 있을 수 있으므로 root 계정의 비밀번호를 설정했다. (학생 본인은 root 계정의 비밀번호를 'root'로 설정했음)

 

 

[그림 21] 외부로부터 해당 DB 접속을 허용

모든 데이터베이스의 모든 테이블에 있어서 root에 대한 접근 권한을 모든 호스트로 지정한다.

 

 

[그림 22] 사용자들의 권한 확인


<2 대의 웹 서버 가상머신에서의 설정>

[그림 23] vm1-eastus 가상머신의 php 버전 확인

첫 번째 가상머신의 PHP 버전을 확인한다. (버전 확인이 안된다면 php 설치)

PHP 7.2.24 버전임을 알 수 있다.

 

 

[그림 24] vm2-eastus 가상머신의 php 버전 확인

두 번째 가상머신의 PHP 버전을 확인한다. (버전 확인이 안된다면 php 설치)

첫 번째 가상머신과 똑같이 PHP 7.2.24 버전임을 알 수 있다.

 

 

[그림 25] vm1-eastus의 IP 주소 확인

ifconfig를 통해 IP 주소를 확인한다.

vnet-eastus-swucloudhw(10.0.0.0/16)에 속하는 vm1은 10.0.3.4 라는 IP 주소를 가진다.

 

 

[그림 26] vm2-eastus의 IP 주소 확인

ifconfig를 통해 IP 주소를 확인한다.

vnet-eastus-swucloudhw(10.0.0.0/16)에 속하는 vm2는 10.0.4.4 라는 IP 주소를 가진다.

 

 

[그림 27] vm3-eastaust에서 mysql 연결 상태를 확인

 

[그림 28] vm1-eastus의 기본 화면이 될 php 파일

 

vm1-eastus의 /var/www/html 의 디렉토리에 기본으로 뜨는 페이지가 될 php 파일을 작성한다.

그 내용에는 DB 연결에 필요한 정보도 포함된다.

(username : root, password : root, 연결할 데이터베이스 : hw_for_cloud, 연결할 테이블 : response1)

 

중요한 포인트 : [그림 5] 에서 확인한 vm3forDB의 사설 IP 주소(172.0.3.4)와 연결시켜 준다. (VPN을 구축했기 때문에 사설 IP를 이용하는 것)

 

 

 

[그림 29] vm2-eastus의 기본 화면이 될 php 파일

 

vm2-eastus의 /var/www/html 의 디렉토리에 기본으로 뜨는 페이지가 될 php 파일을 작성한다.

내용은 vm1-eastus에서 작성한 것과 같지만 연결할 테이블이 response2 라는 점이 다르다.

 


<웹 서비스를 외부에서 접속>

 

에러

[그림 30] 웹 브라우저를 통해 vm1-eastus와 vm2-eastus 의 공인 IP 주소로 접속

웹 브라우저를 통해 vm1-eastus의 공인 IP 주소 40.117.128.66  그리고 vm2-eastus의 공인 IP 주소 52.149.217.157로 접속을 시도하였으나 SQLSTATE[HY000] [2002] Connection refused 에러가 떴다.

 

 

[그림 31] 에러 해결을 위해 mysqld.cnf 파일 수정

 

[그림 32] mysqld.conf 파일

bind-address = 127.0.0.1 이라고 되어있는 설정을 주석처리 해준다.

MySQL은 기본적으로 localhost(127.0.0.1)에서 접근 가능하기 때문에 외부에서 접근하기 위해서는 bind-address를 풀어줘야 한다.

 

 

[그림 33] 웹 브라우저를 통해 vm1-eastus 공인 IP 주소로 접속

response1 테이블과 연결되어 있는 첫 번째 가상머신의 공인 IP 40.117.128.66 로 접속하면 우리가 입력했던 레코드가 보인다. (lastname = Lee)

 

 

[그림 34] 웹 브라우저를 통해 vm2-eastus 공인 IP 주소로 접속

response2 테이블과 연결되어 있는 두 번째 가상머신의 공인 IP 52.149.217.157 로 접속하면 우리가 입력했던 레코드가 보인다. (lastname = Kim)

 


<2 대의 웹 서버 로드밸런싱 설정>

[그림 35] AGW 설정

AGW(Application Gateway)는 웹 트래픽 로드밸런서이다. 

HTTP/HTTPS 수신기의 Routing Rule을 통해 front-end와 back-end를 연결시켜준다. 

 

만들었던 2대의 웹 서버 가상머신(vm1-eastus & vm2-eastus)에 대해 로드밸런싱을 시켜줄 것이므로 

AGW의 가상 네트워크를 2대의 웹 서버 가상머신들의 가상 네트워크와 똑같이 설정해준다. (vnet-eastus-swucloudhw)

서브넷은 2대의 웹 서버와 겹치지 않게 snet03-vnet-eastus-swucloudhw 를 만들어 설정한다.

 

이 AGW의 Front end 주소가 52.188.92.240 인 점에 주목한다.

 

 

[그림 36] back-end pool 설정

AGW의 요청을 받아 처리할 백 앤드 풀에 웹 서버 vm 2대를 대상으로 설정하여 로드밸런싱을 받는다.

 

 

[그림 37] AGW의 동작 과정

 

 

[그림 38] 52.188.92.240 접속 시

웹 브라우저를 통해 52.188.92.240에 접속하니 vm1-eastus의 공인 IP 주소로 접속했던 결과와 똑같이 나온다.

 

[그림 39] 새로고침 시

새로고침을 하니 vm2-eastus의 공인 IP 주소로 접속했던 결과와 똑같이 나온다.

AGW가 성공적으로 로드밸런싱을 수행하고 있다는 것이다.

 


<SSH 연결 차단을 위한 설정>

[그림 40] NSG 설정

NSG(Network Security Group) 설정 추가를 한다.

그 중 인바운드 보안 규칙을 추가해 2대의 웹 서버 가상머신 중 한 대의 가상머신(vm1-eastus)에만 SSH 연결 요청을 차단할 것이다.

 

ssh 차단

[그림 41] vm1-east 에 SSH 연결 요청

NSG에서 vm1-eastus에 대해 SSH로 접속을 시도했으나 Connection timed out 이 뜬다.

성공적으로 인바운드 규칙이 적용된 것이다.

 


<네트워크 구조>

[그림 42] vnet-eastus-swucloudhw의 전체적인 네트워크 구조

 

[그림 43] vnet-eastaust-swucloudhw의 전체적인 네트워크 구조

 

뿌 듯

- 인터넷 이용을 위해선 해당 사이트의 IP 주소를 알아야 하며, 이 주소는 한 눈에 들어오지 않는 숫자로 구성되어 있다.

- 따라서 이를 쉽게 기억하기 위한 이름 체계를 만들었고(FQDN), 사용자들이 사용하는 FQDN을 실제 인터넷에서 필요한 IP 주소로 변환하는 서비스가 필요하며, 이를 DNS(Domain Name Service)라고 한다.

 

DNS

:: 웹(web) 상에서 호스트 컴퓨터가 도메인 이름을 IP주소로 변환하기 위해 DNS 서버에게 질의 응답을 하는 서비스

 

DNS Spoofing

:: DNS 트래픽을 공격자가 가로채고, 위조된 IP 주소로 응답하여 호스트 컴퓨터가 위조된 IP 주소로 접근하게끔 하는 공격

:: DNS 캐시 목록에 위조된 레코드 정보를 추가시켜 Client가 URL을 입력하면 위조된 웹 서버로 접속을 유도하여 정보를 탈취하거나 DNS 서버를 공격한다.

:: DNS 서버 자체를 공격하여 DNS 캐시 목록을 오염시킬 수 있지만, DNS 응답을 가로채기 하여 Client가 위조된 DNS 정보를 이용하도록 만든다. 

:: 공격자는 암호화되지 않은 통신 간의 데이터를 임의로 조작하고 조작된 결과를 전달할 수 있다.

 

:: ARP Spoofing 공격이 선행되어야 한다.

--> 공격자는 게이트웨이와 Client의 MAC 주소를 공격자의 MAC 주소로 속인후, Client의 웹 서버 접속을 기다린다.

더보기

ARP Spoofing

 

:: 로컬 네트워크 (LAN)에서 사용하는 ARP 프로토콜의 허점을 이용하여 자신의 MAC(Media Access Control)주소를 다른 컴퓨터의 MAC인 것처럼 속이는 공격

:: ARP Cache 정보를 임의로 바꾼다고 하여 "ARP Cache Poisoning 공격"이라고도 불린다.

:: 단순히 패킷을 가로채어 훔쳐보는(Sniffing) 수준이 아니라, 가로챈 패킷을 변조한 후 전송하는 공격에도 사용되고 있다.

 

 

- Client가 URL을 이용하여 웹 서버에 접속할 때 자신의 DNS 캐시 목록에서 IP 주소를 찾지 못하면 UDP 프로토콜을 이용하여 로컬 DNS 서버에 웹 서버의 IP 주소를 요청한다.

 

- 이때 DNS 서버보다 가까이 있는 공격자는 DNS 응답 메시지를 먼저 보낼 수 있다.

따라서 Client는 먼저 수신된 위조된 DNS 응답 메시지를 신뢰하여 파밍사이트에 접속하게 되며, 공격자는 아이디와 패스워드와 같은 개인 정보를 중간에서 탈취한다.

 

더보기

UDP(User Datagram Protocol)

:: 전송 계층에서 사용하는 프로토콜로, 연결 설정과 해제 과정이 없는 비연결형 프로토콜

:: 오류 처리 및 패킷 순서 재조합과 같은 제어 기능이 없다

:: 단순히 데이터를 전송하고 수신한다.

:: 데이터의 신뢰성 검증이 필요없고, 데이터의 안전성 보다는 빠른 데이터 처리 및 빠른 전송이 요구되는 곳에 쓰인다.

 

UDP 소켓 통신

:: 서버와 클라이언트의 구분이 명확하지 않다.

(한 쪽이 sendto() 함수 호출로 데이터를 송신할 때 bind()로 특정 포트를 지정하지 않아도 데이터를 수신하는 시스템에서는 recvfrom() 함수의 인자를 통해 보낸 쪽의 IP와 포트 번호 확인이 가능한다.)

:: UDP는 송신자가 일방적으로 데이터를 전달하는 통신 프로토콜로, DNS 요청 과정에서 UDP 포트 53번을 사용한다.

 

DNS Spoofing


<첫 번째 실습>

※ 실습 환경 : 5.10.0-kali3-amd64, Windows 7 

첫 번째 실습

 

1. Target PC에게 ARP Spoofing을 수행한다.

 

-   arpspoof -i[사용할 인터페이스] -t [target이 될 대상의 IP주소] [속일 IP주소]

-   arpspoof -t 192.168.100.142 192.168.100.2 명령어 통해 Arp Spoofing을 수행

 

  Client(192.168.100.142)가 Gateway(192.168.100.2)로 통신을 할 때 이 정보가 Gateway로 가지 않고 Attacker PC에게로 이동하게 된다. Client에게 게이트웨이의 MAC 주소를 공격자의 MAC주소라고 계속해서 응답을 보낸다.

 

-   Attacker PC에서 응답 처리를 해주기 위해서 fragrouter -B1 명령어를 이용해 Client가 정상적으로 통신이 되게 설정한다. (B1 옵션 : 송수신 데이터 변조없이 데이터 그대로를 포워딩 해줌)

 

arpspoof 만을 이용하는 경우에는 희생자가 보내는 데이터들이 공격자로 넘어는 오지만, 공격자가 희생자가 원하는 서비스를 제공하지는 않으므로 응답이 가질 않게 되어 희생자 측에서 이상함을 눈치챌 수 있다.

 

하지만, arpspoof와 함께 fragrouter의 B1 옵션을 이용하게 되면 희생자는 정상적으로 통신이 되면서 희생자의 모든 패킷이 공격자를 통해가게 된다.

 

 

2.  Attacker PC에서 WebServer(apache2)를 실행한다.

 

-   Target PC가 Web브라우저를 통해 접속할 경우 자신이 설정한 웹 페이지를 보여주기 위해서 자신이 임의로 만든 웹 서버를 실행한다.

 

 

3.  Target PC에서 잘 동작하는지 확인

-   Client PC에서 Attacker PC IP 주소를 입력한 후 Attacker PC의 웹 페이지가 잘 접속되는지 확인한다.

 

 

 

4. Attacker PC에서 hosts 파일을 생성한다.

-   Target PC에서 Attacker PC가 원하는 주소를 입력할 때 자신의 사이트를 띄우기 위해 hosts 파일을 작성한다.

 

-   Client가 www.naver.com으로 접속할 경우 192.168.100.137로 이동하게 설정한다.  

 

 

5. Attacker PC에서 DNS Spoofing을 수행한다.

-   dnsspoof 명령어를 사용하여 www.naver.com에 대한 DNS Query 패킷이 위조된 웹 서버인 192.168.100.137로 이름이 해석되도록 설정한다

-   dnsspoof - i [인터페이스] -f [DNS 조회할 파일] 명령어를 입력해 53번 포트를 리스닝 상태로 만든다.

 

 

 

6. Target PC에서 잘 동작하는지 확인한다.

-   DNS 조회를 하기 이전에 이전 DNS 조회 기록을 지우기 위해서 ipconfig /flushdns 명령어를 입력한다.

(이전 기록들이 남아있을 수 있으므로)

 

 

 

공격 실패 시

-  공격이 성공한다면, hosts 파일에 설정한 주소를 입력했을 시 해당 사이트로 이동해야 한다. 

하지만 글쓴이 같은 경우 몇 번을 시도해도 DNS Spoofing 공격을 실패했다.

 

 

공격 성공 시 나오는 페이지

- 공격 성공 시  Client는 www.naver.com을 입력했지만 사이트는 공격자가 임의로 작성한 페이지에 접속이 된다. 

 

- Attacker PC에서 확인하면 Target PC에서 DNS 요청을 하는 것을 알 수 있다.

 



<두 번째 실습>

※ 실습 환경 : 5.10.0-kali3-amd64, Windows 7 

 

두 번째 실습

※ 두 번째 실습에선 DNS Spoofing 공격 결과를 확인하기 위해 마지막에 ping 명령어를 사용할 것이다.

 

 

▷ 실습을 위한 웹 서버 환경 구축 (피싱 사이트를 직접 구축하여 접속시키게 할 것이므로)

 

<Apache와 Tomcat 연동>

- 정적인 HTML, image, CSS 파일의 처리는 아파치가, 동적인  DB연동 및 JSP 파일 처리는 톰캣에 넘겨 효율적으로 이용할 수 있기 때문이다

localhost 접속 시

- 아파치 정상 설치 확인

 

localhost:8080 접속 시 

- 톰캣 정상 설치 확인

 

/etc/apache2/sites-enabled/000-default.conf 파일 설정

- 아파치와 톰캣을 연동하기 위한 커넥터를 설치하는 과정이다. 

 해당 파일에 JKMount /* ajp13_worker 구문을 추가한다.(적용할 톰캣의 URL 설정)

 

/etc/tomcat8/server.xml 파일 설정

- <Connector> 태그가 있는 부분의 주석을 제거해준다.

 

apache2와 tomcat9 연동 성공

- 설정 후 Apache & Tomcat 데몬을 재시작한 후 정상적으로 둘이 연동되었는지 확인한다.

 

 

1. 피싱 웹 서버 구축

웹서버 접속(http://localhost) 테스트

- 웹 서버 구축을 위해 Apache 웹 경로에 있는 기존 index.html 파일을 삭제한 후 원하는 대로 수정한다.

index.html 파일의 경로는 다음과 같다. /var/lib/tomcat8/webapps/ROOT/index.html 

그 후 localhost에 접속하면 위 그림처럼 뜬다.

 

 

2. 공격자 IP 확인 후, DNS 스푸핑 파일 설정

vi dnsspoof.hosts 후 cat 명령어를 통해 확인

- 왼쪽에는 공격자 IP를, 오른쪽에는 공격하고자 하는 사이트를 임의의 hosts 파일에 등록한다.

 

3. ARP 스푸핑과 패킷 릴레이

ARP Spoofing

- arpspoof 툴로 스푸핑 공격을 실행한다.

fragrouter 명령어 실행

- - Attacker PC에서 응답 처리를 해주기 위해서 fragrouter -B1 명령어를 이용해 Client가 정상적으로 통신이 되게 설정한다. (B1 옵션 : 송수신 데이터 변조없이 데이터 그대로를 포워딩 해줌)

# arpspoof 만을 이용하는 경우에는 희생자가 보내는 데이터들이 공격자로 넘어는 오지만, 공격자가 희생자가 원하는 서비스를 제공하지는 않으므로 응답이 가질 않게 되어 희생자 측에서 이상함을 눈치챌 수 있다.
# 하지만, arpspoof와 함께 fragrouter의 B1 옵션을 이용하게 되면 희생자는 정상적으로 통신이 되면서 희생자의 모든 패킷이 공격자를 통해가게 된다.

 

 

4. DNS 스푸핑 공격 수행

dnsspoof 명령어 실행

- 앞서 만들었던 hosts 파일을 참조해 dnsspoof 공격을 시작한다.

 

 

5. 공격이 성공되었는지 클라이언트에서 확인

공격 실패 시

- 위 사진과 같이 공격이 실패했을 경우에 클라이언트가 구글의 올바른 IP주소를 확인한다.

dns 정보 삭제

- 클라이언트의 cmd 창을 관리자모드로 실행한 후, DNS 정보를 삭제한다

ipconfig /flushdns 명령어를 사용한다.

 

공격 성공 시

- dns 스푸핑 공격이 성공하면 www.google.com에 ping 요청을 보냈지만 위 그림과 같이 공격자의 IP주소를 확인하고 있는 것을 알 수 있다. 

 

 


<DNS Spoofing 공격 차단 방법>

- 브라우저에 접속할 도메인을 입력하면 반드시 DNS Query가 발생하지는 않는다. 

1) 우선 이전에 같은 사이트에 접속한 적이 있는지 확인하기 위해 캐시에 해당 도메인에 대한 IP주소가 존재하는지 읽어본다. 
2) 만일 캐시에 IP가 존재하지 않는다면 
3) hosts 파일에 적혀진 도메인 이름에 대한 IP주소를 해석한다. 
→ 그렇기 때문에 중요한 사이트의 IP주소를 hosts 파일에 미리 적어두게 되면
DNS Query 없이 바로 hosts 파일에 적혀진 IP 주소로 접속하므로 DNS spoofing 공격을 방어할 수 있다

 

 

hosts 파일 설정

- Window7 에서 hosts 파일의 경로는 다음과 같다. 

C:\Windows\System32\drivers\etc 

 

wireshark로 확인

- 파이어폭스를 통해 www.google.com에 접속한 후 와이어샤크로 패킷을 확인해보면, hosts 파일에 저장한 IP로 통신이 발생하고 있음을 확인할 수 있다.  

 

 

 

'Project > Network' 카테고리의 다른 글

Hancitor Analysis by Wireshark (4)  (0) 2021.08.19
Hancitor Analysis by Wireshark (3)  (0) 2021.08.19
Hancitor Analysis by Wireshark (2)  (0) 2021.08.19
Hancitor Analysis by Wireshark (1)  (0) 2021.08.19

 

문제

아무 문자를 입력해봐도 변화가 없다.

소스코드

 

이 문제에서 포인트가 되는 부분은

 

1) where 문의 뒷 부분에서 id=' 의 작은 따옴표(')가 제대로 안 닫혀있다는 점

2) 입력값에 있는 '는 str_replace을 통해 ' '로 바꾼다는 점

3) substr를 통해 입력값 중 첫 번째 문자부터 15번째 문자까지만 id에 저장한다는 점

 

이라고 생각했다.

 

 

15번째에서 잘린다면 마지막 15번째 문자열에 '를 입력해서 작은 따옴표가 2개가 되는 것을 방지할 수 있을거라 예측

(where문을 완성시키기 위해 '를 넣어야 하므로)

where 조건 중 id 값은 길이가 14를 넘어가면 안 된다는 점을 주의

 

 

따라서 아래와 같이 입력해주었다.

실제로 member 테이블에 있을 것만 같은 guest 문자열을 입력한 후 공백을 통해 14번째 자리까지 채웠고

'를 15번째에 입력해줬다.

 

 

'WEB > WEB Hacking' 카테고리의 다른 글

[Webhacking.kr] Challenge(old) 55번 풀이  (0) 2021.11.10
wfuzz  (0) 2021.07.10
[Webhacking.kr] Challenge(old) 38번 풀이  (0) 2021.06.04
[Webhacking.kr] Challenge(old) 36번 풀이  (0) 2021.06.03
[Webhacking.kr] Challenge(old) 33번 풀이  (0) 2021.06.02

문제
페이지 소스코드
admin 입력 결과

admin을 입력하니 you are not admin 이라 한다.

 

admin.php 접속

admin.php에 접속해보니 밑에는 내 PC에서 순서대로 입력했던 값이 나와있는 것을 확인했고, 위쪽에 183.98.10.141로 접속한 PC의 명령어가 그대로 나와있다. admin으로 접속하기 위한 시도인 듯 하다.

 

이 페이지에서 기록하는 Log는 IP:입력값 형태인 듯 싶다. IP:admin이면 풀리는 문제인 것 같은데 admin을 입력했을 때는 여기에 기록은 안되고 페이지에 단지 you are not admin이라는 문자열만 띄운다.

그리고 보통 개행문자를 이용해 Log Injection을 한다고 하는데 앞의 시도를 보면 이 문제에선 왜인지 그게 안통하는 듯 하다.

 

나의 시도,,,,,

 

그러다가 아예 입력을 여러 줄로 할 수 있다면? 이라는 생각이 들어 페이지 코드를 직접 수정하였다.

html 코드 수정

text 타입 대신에 여러 줄을 쓸 수 있는 textarea를 넣어 html 코드를 수정한 후 Log Injection을 시도하였다.

 

해결

'WEB > WEB Hacking' 카테고리의 다른 글

wfuzz  (0) 2021.07.10
[Webhacking.kr] Challenge(old) 39번 풀이  (0) 2021.06.07
[Webhacking.kr] Challenge(old) 36번 풀이  (0) 2021.06.03
[Webhacking.kr] Challenge(old) 33번 풀이  (0) 2021.06.02
[Webhacking.kr] Challenge(old) 27번 풀이  (0) 2021.05.30

문제

"현재 디렉토리에서 vi editor를 사용해 index.php 파일을 수정하는 동안, 정전으로 인해 소스코드가 사라지게 되었다.

복구시키는 것을 도와달라" 고 하고 있다.

 

 

vi 편집기에 대한 지식을 요구하는 문제이다. 잘 몰랐기 때문에 이 부분에 대해서 찾아보았다.

vi 편집기를 사용하다가 파일작업이 정상종료 되지 않으면 임시 스왑파일 swp이 생성된다.
vi 에디터를 정상적으로 종료하면 자동으로 제거되는 파일이지만, 이 파일이 남아있다는 것은 정상종료를 하지 않은 것이다. (참고로 파일 이름 앞에 . 이 있다는 것은 숨김파일을 의미함)

 

그러면 이 문제에서 index.php 작성 중 정상적 종료를 하지 못했으므로 .index.php.swp 파일이 생겼을 것이다.

 

URL에 입력

.index.php.swp라고 입력했더니 swp 파일이 다운로드 받아졌다.

 

열어보니 이러한 구성을 띄고 있었다. 해석할 수 없기 때문에 다른 에디터로 열어보았다.

 

$flag 값 발견

Auth 페이지에 들어가 해당 flag 값을 입력했더니 문제 풀이에 성공하였다.

이미지 블러링(image blurring)

:: Image Blurring은 LPF를 이미지에 적용하여 얻을 수 있다. 고주파영역을 제거함으로써 노이즈를 제거하거나 경계선을 흐리게 하는 것이 목적. 

(LPF, HPF는 이전 글을 보면 설명이 되어있다.)

 

OpenCV에는 4가지 형태의 blurring 방법을 제공하고 있다.

1. Averaging
:: Box 형태의 커널을 이미지에 적용한 후 평균값을 box의 중심점에 적용

2. Median Filtering
:: 커널 윈도우와 픽셀의 값들을 정렬한 후에 중간값을 선택하여 적용
점 잡음(점처럼 찍힌 노이즈)을 제거하는데 효과적

3. Gaussian Filtering
:: Gaussian 함수를 이용한 커널을 적용
이미지의 전체적으로 밀도가 동일한 노이즈 , 백색노이즈를 제거하는데 가장 효과적

4. Bilateral Filtering
:: 양방향필터는 경계선을 유지하면서 Gaussian Blur 처리
Gaussian 필터를 적용하고 , 또 하나의 Gaussian 필터를 주변 픽셀까지 고려하여 적용하는 방식
경계면을 지키며 표면의 질감 등을 제거하는데 효과적

 

1. 평균 블러

:: 균일한 값을 가지는 커널을 이용한 이미지 필터링. 커널 영역내의 평균값으로 해당 픽셀을 대체

 

OpenCV에선 blur 함수로 구현되어 있다.

 

blur(src, ksize)

  • src: 원본 이미지
  • ksize: 커널 크기 (1보다 큰 홀수)

평균 블러 적용

 

2. 중앙값 블러

:: 평균이 아닌 중앙값으로 해당 픽셀을 대체.

kernel window와 pixel의 값들을 정렬한 후에 중간값을 선택하여 적용한다. 점 모양의 잡음을 제거하는 데 효과적이다.

OpenCV에서는 medianBlur 함수를 사용한다.

 

medianBlur(src, ksize)

  • src: 원본 이미지
  • ksize: 커널 크기 (1보다 큰 홀수)

중앙값 블러 적용한 이미지

 

3. 가우시안 블러

:: box filter는 동일한 값으로 구성된 kernel을 사용하지만, Gaussian Filter는 Gaussian함수를 이용한 Kernel을 적용

즉, kernel 행렬의 값을 Gaussian 함수를 통해서 수학적으로 생성하여 적용

 

OpenCV에서는 GaussianBlur로 구현되어 있다.

 

GaussianBlur(src, ksize, sigmaX)

  • src: 원본 이미지
  • ksize: 커널 크기(양수이면서 홀수)
  • sigmaX: 표준편차

백색노이즈가 있는 이미지를 가우시안 블러 처리

 

4. 양방향 필터링

:: 가우시안 필터링을 쓰면 이미지의 경계선도 흐려진다는 문제점이 있다. 따라서 경계선을 유지하면서 Gaussian 블러처리를 하는 것이 필요하다.

 

Gaussian 필터를 적용하고, 또 하나의 Gaussian 필터를 주변 pixel까지 고려하여 적용하는 방식이다.

OpenCV에서는 bilateralFilter 함수로 구현되어 있다.

 

bilateralFilter(src, d, sigmaColor, sigmaSpace)

  • src: 원본 이미지
  • d: 커널 크기
  • sigmaColor: 색공간 표준편차. 값이 크면 색이 많이 달라도 픽셀들이 서로 영향을 미친다.
  • sigmaSpace: 거리공간 표준편차. 값이 크면 멀리 떨어져있는 픽셀들이 서로 영향을 미친다.

 

 

참고 사이트

https://datascienceschool.net/03%20machine%20learning/03.02.02%20%EC%9D%B4%EB%AF%B8%EC%A7%80%20%ED%95%84%ED%84%B0%EB%A7%81.html

 

https://opencv-python.readthedocs.io/en/latest/doc/11.imageSmoothing/imageSmoothing.html

'Project > Image Handling' 카테고리의 다른 글

이미지 필터링  (2) 2021.06.03
이미지 임계처리  (0) 2021.06.02
이미지 처리  (0) 2021.06.01

이미지 필터링(image filtering)

:: 필터(filter) 또는 커널(kernel) 또는 윈도우(window)라고 하는 정방행렬을 정의한 후 이 커널을 이동시키면서 같은 이미지 영역과 곱하여 그 결과값을 이미지의 해당 위치의 값으로 하는 새로운 이미지를 만드는 연산. 기호ⓧ를 사용

 

더보기

이미지도 주파수로 표현 가능

사물을 촬영할 때 사물과 배경의 사이 사물의 테두리 경계면이 고주파 영역이고, 일반적인 배경은 저주파이다.

 

LPF vs HPF

Low-Pass-Filter 저역 통과 필터 : 저주파만 통과시키는 필터

High-Pass-Filter 고역 통과 필터 : 고주파만 통과시키는 필터

 

LPF를 사용하면 고주파가 통과가 안되니 경계면이 유연해지거나 노이즈 제거, 블러 처리를 할 수 있고

HPF를 사용하면 이미지에서 경계선을 찾을 수 있다.

 

Kernel(커널)은 행렬을 의미하는데, 커널의 크기가 크면 이미지 전체가 blur 처리가 많이 된다. 

 

Filter 적용 방법

- 이미지의 픽셀 값의 중심으로부터 해당 커널 만큼의 영역을 평균하여 해당값을 커널값으로 나누고 이 값을 중심 픽셀값으로 취한다.

 

5x5 행렬

5x5 행렬에서. 이미지 중 하나의 픽셀을 지정한다고 하면, 그 픽셀을 중심으로 하는 5x5 범위의 모든 픽셀값을 더하고 그 값을 25로 나누고 나눈 값을 중심 픽셀값으로 정하는 것이다.

 

OpenCV는 cv2.filter2D()라는 함수를 이용해 이미지에 kernel(filter)를 적용하여 이미지 필터링이 가능하다.

이미지 픽셀 값을 해당 픽셀의 이웃과 평균하여 그 값을 취하는 averaging filter라고 한다.

 

filter2D(src, ddepth, kernel[, dst[, anchor[, delta[, borderType]]]])

  • src: 필터할 이미지
  • ddepth: 이미지 깊이(자료형 크기). 영상데이터를 저장하기 위해 사용되는 비트의 수. -1이면 소스이미지과 동일
  • kernel: 커널 행렬 (np.ones() 함수를 사용하여 행렬 생성 후 행렬 값으로 나눈 값이 포함)

+) np.ones(shape, dtype=None, order='C') : 지정된 shape의 배열을 생성하고 모든 요소를 1로 초기화. 

 

커널 사이즈에 따른 이미지 필터링 결과

 

참고 사이트

https://datascienceschool.net/03%20machine%20learning/03.02.02%20%EC%9D%B4%EB%AF%B8%EC%A7%80%20%ED%95%84%ED%84%B0%EB%A7%81.html

 

https://opencv-python.readthedocs.io/en/latest/doc/11.imageSmoothing/imageSmoothing.html

'Project > Image Handling' 카테고리의 다른 글

이미지 블러링  (0) 2021.06.03
이미지 임계처리  (0) 2021.06.02
이미지 처리  (0) 2021.06.01

+ Recent posts