안녕하세요. 저번에 공지한대로 이번 포스팅에서는 콘솔창을 띄우지 않고 프로그래밍을 해보겠습니다.

visual stdio를 열어 프로젝트를 만듭니다.

win32 응용 프로그램을 만들기 위해 Win32 프로젝트를 선택하여 프로젝트를 만듭니다.

만들 프로그램을 windows 응용 프로그램으로 선택하고 빈 프로젝트를 체크해 준 다음 마침을 누릅시다. 가끔 사람들이 빈 프로젝트가 뭐냐고 물으시는 분 들이 있는데 말 그대로 비어있는 프로젝트를 뜻합니다.

빈 프로젝트를 체크해제하고 만들 시 visual stdio에서 지정한 기본 main 함수가 미리 적혀있는 것을 볼 수 있습니다.

아래는 빈 프로젝트를 체크해제하고 만든 프로젝트입니다.

보시다시피 상당한 지식을 요구하는 코드가 자동으로 적혀있는 것을 볼 수 있습니다. 즉 전문가용 옵션입니다. 우리는 전문가가 아니니까 그냥 빈 프로젝트 옵션을 사용합시다.

프로젝트를 만드셨으면 소스를 만듭시다.

c언어로 작성해야하니 c++ 파일을 선택하시고 소스파일의 확장자를 c로 맞춥시다.

여기까지 하셨으면 이제 소스를 작성할 차례입니다. 미리 제가 작성한 소스를 한 번 봅시다.

네 소스코드는 콘솔프로그래밍과 별 차이가 없습니다. 하지만

main부분이 상당히 다르다는 것을 느낄 수 있습니다. 

- int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,int nCmdShow)

이번 포스팅의 핵심부분입니다. 하나씩 살펴봅시다.

*WINAPI WinMain

WINAPI란 windows api를 뜻합니다. 즉 windows에서 사용하는 api라는 뜻입니다.

여기서 api가 무엇인고하니 api는 Application Programming Interface의 약자를 뜻합니다.

해석하면 응용프로그램 프로그래밍 인터페이스를 뜻하는데 인터페이스가 두 장치 간의 상호작용을 위한 매개체를 뜻하므로 풀이하면

응용프로그램을 프로그래밍하기 위한 매개체를 뜻합니다. 쉽게 말하면 응용프로그램을 만들기 쉽게 해주는 규격 같은 것입니다.

즉 winapi는 윈도우에서 응용프로그램을 프로그래밍할 때 도움을 주는 인터페이스를 의미합니다.

정리하면 WINAPI WinMain이란 WINAPI 호출규약인 WinMain함수를 선언하였다. 라고 보시면 됩니다. 일반 콘솔 프로그래밍에서는 컴파일러가 main함수를 찾는 것이 비해 응용 프로그래밍에서는 컴파일러가 WinMain함수를 찾습니다. 그러므로 WinMain함수를 선언해 주었습니다.

이러한 WinMain은 인자를 다음과 같이 받습니다.

보시게 되면 제가 WINAPI를 넣었던 자리에 CALLBACK라고 적혀있는 것을 볼 수 있습니다. 사실 이자리는 함수호출규약을 정하는 자리입니다. 

함수호출규약이 무엇이냐면 함수를 호출할 때 스택을 정리하는 규약을 정해놓은 것입니다. 일반적으로 __cdecl와 __stdcall가 있는데 일반 콘솔 프로그래밍에서 함수를 호출 할 경우에는 __cdecl를 쓰지만 응용프로그래밍을 할 경우에는 __stdcall 방식을 씁니다. 좀더 자세히 알아보기 위해 실습을 해 봅시다.

WinDef.h를 작성하시고 문서를 열어봅시다. WinDef 헤더파일은 여러 자료형을 정의해 놓은 문서입니다.

문서를 찾아보면 위와 같이 정의되 있는 곳을 찾을 수 있습니다.

MSDN의 CALLBACK과 제가 작성한 WINAPI의 정의된 값을 보면 __stdcall라고 정의되어있습니다. 즉 함수호출규약을 뜻합니다.

즉 CALLBACK 자리에는 CALLBACK이 와도 되고 WINAPI도 와도 되고 __stdcall이 와도 된다는 것입니다. 

그러면 꼭 함수 호출 규약을 적어야 하나? 라는 의문이 들 수 있습니다. 실험 결과 규약을 적지 않아도 프로그램이 정상적으로 실행되는 것을 볼 수 있었습니다. 하지만 밑의 결과를 보면

WinMain의 호출규약은 __stdcall이어야 한다고 경고가 나옵니다.(에러 아닙니다)

그래서 저는 저 자리에 WINAPI를 적어주었습니다.

이제 인자들을 차례대로 살펴 봅시다.

hInstance

자료형이 HINSTANCE입니다. HINSTANCE는 핸들 인스턴스의 약자이며 쉽게 말하면 프로그램 자체의 주소라고 보시면 됩니다. HWND가 프로그램 내의 윈도창의 번호라고 한다면 HINSTANCE는 프로그램의 번호라고 보시면 됩니다.

hPrevInstance

자료형이 HINSTANCE입니다. 즉 프로그램 자체의 주소를 받는다는 것은 앞의 인자와 동일하나 이 인자는 이 프로그램의 주소가 아닌 앞에 실행된 프로그램의 주소를 받습니다. 그런데 이 인자는 16비트 환경일 때 사용한 인자이며 현재 32비트 환경에서는 사용되지 않습니다. 그래서 기본적으로 NULL값이 인자로 들어갑니다.

*lpCmdLine

자료형이 LPSTR인 이 인수는 이 프로그램의 이름 혹은 경로를 유니코드체계로 받습니다.

*nCmdShow

자료형이 INT인 이 인수는 윈도우가 표시되는 방법을 정수형으로 받습니다.

자 여기까지가 WinMain의 설명입니다. 기본적으로 WinMain를 사용할 시에는 저 4개의 인자를 적어주어야 합니다.

추가로 덧붙이자면 위의 인자이름들은 가독성을 위해 MSDN에서 정해놓은 인자이므로 굳이 인자이름을 똑같이 적을 필요는 없습니다.

자료형만 맞추고 인자 이름이 예약어가 아니라면 정상적으로 실행이 됩니다.

자 이제 소스설명이 끝났으니 한번 실행 해 봅시다.

콘솔창이 뜨지 않는 것으로 보아 정상적으로 실행됐음을 알 수 있습니다.

다음 포스팅은 이렇게 제작한 프로그램을 리버싱하는 것을 올리겠습니다. 참고로 리버싱 카테고리에 올릴 예정입니다.

이상으로 포스팅을 마치겠습니다.





Posted by englishmath
,

안녕하십니까? 이번 포스팅의 주제는 abex crack me 만들기 입니다.

abex crack me의 동작화면을 한 번 보겠습니다.

간단하게 메세지박스 2개가 출력되는 프로그램입니다.

그럼 이것을 직접 c로 구현해보겠습니다.

저는 visual studio로 작성하겠습니다.

(참고로 저는 visual studio 2010 express 입니다.)


자 소스를 이렇게 작성하였습니다. 한줄씩 설명해드리겠습니다.

-  #include <windows.h> 

windows.h 헤더파일을 선언합니다. 메세지를 띄우기 위한    MessageBox함수와 GetDriveType함수를 사용하기 위해서입니다.

-  int EAX,ESI = 0 

연산에 필요한 변수 EAX와 ESI를 선언하였습니다.

- MessageBox (NULL, L"Make me think your HD is a CD-Rom.", L"abex' 1st crackme", MB_OK);

MessageBox함수입니다. 말 그대로 메세지박스를 띄우기 위한 함수입니다. 자세히 알아보기 위해 MSDN을 참고하겠습니다.

인자가 총 4개입니다. 하나하나씩 살펴 봅시다.

 * hWnd

  첫번 째 인자인 hWnd는 자료형이 HWND입니다. 이 HWND라는 것이 핸들윈도우의 약자를 뜻하는데 이 자료형으로 선언된 변수는 윈도우 창을 식별할 때에 쓰입니다. 

사실 이것을 정확하게 이해할려면 handle에 대한 개념을 알아야 하는데 너무 복잡해지니 그냥 넘어갑시다.

아무튼 결론만 말하면 이 hwnd는 메세지 상자의 소유자에 대한 핸들을 뜻합니다. 우리는 딱히 소유자를 정할 필요가 없으니 NULL값을 주었습니다.

* lpText

앞의 글자는 대문자 I가 아닌 소문자 L입니다. 유념하시기 바랍니다.

이 인자는 메세지창에 표시되는 문자열을 뜻합니다. 그런데? 자료형이 LPCTSTR이죠?

이 것을 간단하게 설명해드리겠습니다.

문자열을 저장하는 자료형이 char인것은 잘 아시죠? 그런데 사실 문자열을 저장하는 자료형이 제법 많습니다.

char, wchar, tchar, LPSTR, LPCSTR, LPCTSTR 등이 있습니다..

다른 자료형도 설명해주면 좋겠지만 그렇게 되면 너무 복잡해지므로 LPCTSTR만 설명하겠습니다.

먼저 LPCTSTR을 설명하기 전에 코드를 잠깐 설명하겠습니다.

코드는 크게 3종류로 나뉩니다.

싱글바이트코드, 멀티바이트코드, 유니코드로 나뉩니다.

싱글바이트 코드는 다른 말로 아스키코드라고도 하며 1바이트로 표현 가능한 문자들을 모아놓은 코드 체계입니다.

멀티바이트코드는 아스키코드문자 집합에 2바이트로 표현가능한 특정 문자를 넣은 코드체계입니다. ex)한글 등

유니코드는 전 세계의 문자를 2바이트로 표현가능하도록 규정해 놓은 코드체계입니다.

여러 코드가 나왔는데 이러한 코드를 설명한 이유는 이 코드 체계를 사용하는 자료형이 따로 나뉘어져 있기 때문입니다. 아래를 살펴보시면

싱글코드 체계를 사용하는 자료형

- char 등

멀티바이트 코드체계를 사용하는 자료형

- char *, const char * 등

유니코드 체계를 사용하는 자료형

- wchar_t, wchar_t *, TCHAR, LPSTR, LPCSTR, LPCTSTR 등

자 여기까지 읽으셨으면 우리가 찾는 LPCTSTR이 유니코드 체계를 사용하는 자료형이라는 것을 알 수 있습니다. 여기서 세부 설명을 하면

LP는 long pointer 즉 *를 의미하고 C는 const, T는 TCHAR의 T, STR은 String 입니다.

즉 LPCTSTR은 const TCHAR * 라고 생각하시면 됩니다. const char * 이 멀티바이트 코드체계를 사용하는 것에 비해 LPCTSTR은 유니코드체계를 사용합니다.

너무 이야기가 길어졌군요.  결론만 얘기하면 자료형이 LPCTSTR인 인자는 const char* 형식으로 값을 넣을 수 없다는 것입니다. 

이렇게 const char* 식으로 값을 넣으면 에러가 뜹니다. 그럼 어떻게 해야 할까요?

이럴때 대문자 L을 사용합니다. 즉 L"문자열" 이렇게 사용합니다.

L이 무엇이냐면 선언입니다.

즉 L 뒤에 오는 문자열이 유니코드 문자열이다 하고 선언해주는 것이지요.

그냥 글자를 적으면 이 글자가 멀티바이트코드체계 문자열인지 유니코드체계 문자열인지 컴퓨터가 인식을 하지 못합니다. 그래서 문자열 앞에 L을 붙임으로써 이 문자열이 유니코드체계문자열임을 선언하겠다라는 뜻입니다.

다음 인자로 넘어갑시다.

* lpCation 

  자료형이 LPCTSTR인 이 인자는 메세지 창의 제목을 뜻합니다. LPCTSTR은 설명했으니 넘어갑시다.

* uType

자료형이 UINT입니다. INT랑 비슷한 자료형인데 INT는 음수까지 저장가능한 것에 비해 UINT는 양수만 저장가능합니다. 하지만 INT보다 많은 범위의 양수를 저장할 수 있습니다.

여기 인자는 메세지에 표시되는 버튼을 뜻합니다. 여기서는 확인 버튼만 필요하므로 이미 정의되어 있는 MB_OK 라는 인자를 사용하였습니다. 

길고 긴 Messagebox 함수 설명이 끝났군요. 혹시 따로 궁금하신 분이 있다면 댓글에 질문을 해주시면 답변드리겠습니다.

- EAX = GetDriveType(L"C:\\");

GetDriveType은 현 컴퓨터의 디스크 드라이브 타입을 가르쳐주는 함수입니다.

MSDN의 설명을 봅시다.

인자가 하나 뿐이군요. lpRootPathName입니다. 자료형은 LPCTSTR인데 설명했으니 넘어갑시다. 

이 인자가 받는 값은 루트 경로를 뜻합니다. 즉 드라이브의 루트 디렉토리 경로를 인자로 받습니다. C드라이브의 루트 디렉토리가 어딜까요? 물론 다들 아시겠지만 확인을 위해 C디스크 안의 아무 폴더나 들어가봅시다.

C드라이브의 프로그램 파일로 들어갔을 때의 폴더주소입니다. 최상위의 경로가 C: 라고 되어있지요? 즉 드라이브의 루트 디렉토리 경로는 C: 입니다. 다만 MSDN의 설명을 참고해보니 경로 끝에 역슬래시(\)가 필요하다고 합니다. 즉 인자로

C:\\가 들어갑니다.

뭔가 이상하지 않습니까? \가 2개나 있습니다. c언어를 잘 배우신 분이라면 특수문자를 표기할 때 \를 붙여야 한다는 것을 아실 겁니다. 

ex) \/, \%, \' , \\ 등

자 이 다음은 설명이 별로 없습니다.

EAX와 ESI를 연산하고 

EAX와 ESI의 값을 비교하여 두 값이 다르면 실패 메세지 박스를 띄우고

성공하면 성공메세지 박스를 띄우는 겁니다.


자 소스코드 설명이 끝났으니 프로그램을 실행시켜 봅시다.

자 이것으로 abex crack me 만들기를 마치....

지 않아야겠죠?

제가 만든 프로그램과 일반 abex crack me가 똑같아 보이십니까? 아니죠?

일반 abex crack me를 실행 시켰을 때 저런 콘솔창 나타나던가요? 아니죠?

저런 콘솔창이 나타나는 이유는 우리가 프로그램을 짤 때 프로젝트 종류를 콘솔 응용 프로그램으로 했기 때문에 저런 콘솔창이 나타는 것입니다.

쓸데 없이 콘솔창이 나오니 멋없어 보이죠? 

그래서 다음 포스트엔 이 콘솔창이 안뜨게 프로그래밍을 해보겠습니다.

즉 콘솔 기반 프로그래밍이 아닌 응용 프로그래밍으로 해보겠습니다.

이상으로 포스팅을 마치겠습니다.

감사합니다.






Posted by englishmath
,

안녕하십니까. 최근 따로 공부를 한다고 블로그 관리가 소홀했던 점 일단 사과드립니다.

이번 카테고리는 직접 코드엔진의 프로그램을 C언어로 만들어보고 그리고 직접 만든 프로그램을 분석하는 식으로 진행할 예정입니다.

왜 이런 방법을 택했느냐고 하니...

솔직히 리버싱이라고 해도 남이 만든 프로그램을 리버싱하면서.. 똑같은 key값 찾기 알고리즘 분석해서 이름이 ~~인 패스워드 찾기 등.. 솔직히 같은 패턴에 너무 질려버렸습니다. 

그래서 이번엔 조금 재밌게 리버싱을 해보고자 직접 프로그램을 제작해보고 그리고 직접 만든 프로그램을 리버싱해보면 어떨까 하고 생각이 들어 이 카테고리를 제작하게 되었습니다.

다음 포스팅은 CodeEngn basic rce level1에 쓰인 프로그램인 abex crack me 1을 한번 c로 만들어보겠습니다.

많이 부족하지만 앞으로 잘 부탁드립니다.

Posted by englishmath
,