오늘은 데이터를 저장하는 방식에 대해 이야기해보겠다.

크게 나누면 메모리를 이용하는 방식과 스택을 이용하는 방식이 있다.

그 중 메모리를 이용하는 방법을 알아볼 것이다.

먼저 데이터 단위이다.
* 데이터의 기본 단위
Unit  bytes  Letter
byte  -> 1 bytes : 표현 B
word -> 2 bytes : 표현 W
double word -> 4 bytes : 표현 D
quad word -> 8 bytes : 표현 Q
ten bytes -> 10 bytes : 표현 T
paragraph -> 16 bytes

* 데이터를 저장하기 위해 사용가능한 메모리
1. 데이터 메모리 : C에서는 전역변수 개념

1) 초기화된 데이터 메모리 영역 :.data
-> 지난 시간까지 사용했던 영역이다.
-> 중간에 type이 db라고 써있는 것에 대해 설명하자면 data 영역에서는 앞에 d를 붙여줘야한다.
    그 뒤에 나오는 것은 데이터 단위로 b는 byte로 1 바이트를 나타낸다.

2) 비초기화된 데이터 메모리 영역 : .bss
중간에 type에 앞쪽에 res를 적어주고 그 뒤에는 데이터 타입을 적어준다.
ex) resb

어셈블리 기본 명령어 구조(인텔기반)
- 명령어( pushfd, nop, ret,  ... ) 피연산자가 없는 경우도 있다. 단일명령어형태
- 명령어 피연산자( pop esp,      jmp addr, ...)
- 명령어 피연산자1, 피연산자2 ( mov ebx, 2  ...)
- 명령어 피연산자1, 피연산자2, 피연산자3 ( mul, ...)

* mov 명령어
mov : 데이터 이동
 mov dst, src
- dst에 올수 있는 것은 메모리와 레지스터 외에 다른 값이 올 수 없다.
- src : 메모리, 레지스트리, 일반 값 전부 다 올 수 있다.

이것들을 이용해 실습하면서 확인해보겠다.
먼저 data 영역에 데이터를 저장하고 출력해보겠다.




(어셈블 코드)



이 코드를 실행하면 numbers에 있는 값들이 출력될까?
실행해보면



(실행결과)



우리가 저장한 값은 전혀 아니라는 것을 확인 할 수 있다.
이 값은 numbers의 주소 값이다.
기본적으로 전달할때 어셈블리언어에서는 주소를 전달한다.

그렇다면 data영역에 numbers 에 우리가 1,2,3,4,5 를 저장했는데 이 값을 출력하려면 어떻게 해야할까?



(출력 코드)



이런식으로 [ ] 브라켓에 담아주면된다.
이렇게 표현을 하면 C언어에서 포인터 같은 역할을 하게된다.
주소값이 아닌 그 주소에 있는 데이터 값을 가져온다.
위 코드를 실행하면 1이 출력이 될것이고
그렇다면 그 다음 값인 2를 출력하려면?



(2 출력 코드)



DWORD가 4바이트이므로 4바이트+ 시켜준 주소값으로 브라켓으로 값을 가져오면 된다.



(실행모습)



2가 출력되는 것을 확인 할 수 있다.

DWORD 써준이유?
numbers 라고 우리가 주소값을 전달해주는데 얼마나 가져오라는 말이 없다.
즉 이 말을 안써주면 어디까지 우리가 가져와야하는지 모르니까 DWORD처럼 가져올 단위를 적어줘야한다.
레지스트리에서 안쓴 이유는 레지스트리 이름 자체에 크기를 뜻하기 때문이다.

이번엔 bss 영역에 초기화 되지 않은 변수들에다가 값을 저장하고 그 값을 출력해보겠다.



(bss 코드)



mov 명령어를 통해 number의 위치에 데이터를 10을 저장한다.
그 후 number 위치의 값을 가져와 출력한다.



(실행 결과)



실행 결과 우리가 10을 너어주었는데
10이 잘 출력된 것을 확인 할 수 있었다.




7번째로 푼 문제이다~!

이 문제는 굉장히 흥미로웠다.!



(WTF_CODE 문제)



아래는 문제 페이지다.




(문제페이지)



여기서 소스코드를 다운받아서 열어보면



(소스코드)



...
?

띠용 아무것도 안보인다.

아하! 이게 헥스에디터로 봐야하나? HxD로 열어주니



(소스코드)



모스부호인가??
모스부호면 패스해야하나.. 싶었는데 ws 확장자가 뭔지 궁금해서
검색해보니 문제의 의도를 쉽게 알 수 있었다.
바로 화이트스페이스 라는 기괴한 프로그래밍 언어를 소개하는 문제인거 같았다.




(화이트스페이스)



아..! 이문제를 풀면서 이런 프로그래밍 언어도 있구나!
진짜 재밌는 언어네 라고 웃으면서 알아보았던 문제이다.

이제 재밌게 내용을 봤으면 풀어야할 시간...!

공백과 탭과 개행문자를 일일이 해석해야하는건가?.. 떨려왔지만
convert해주는 사이트를 발견해서..(감사합니다.)
행복했다.




(변환 사이트)



이 사이트에서 변환안해도 바로 실행시킬 수도 있었는데
실행시키니 창이 하나떴다.



(문제 해결)



신기했던 문제이다.


'WarGame > 500 Project' 카테고리의 다른 글

(9/500) Wargame.kr - md5_compare  (0) 2017.04.13
(8/500) Wargame.kr - fly me to the moon  (0) 2017.04.13
(6/500) Wargame.kr - flee button  (0) 2017.04.11
(5/500) Wargame.kr - QR Code Puzzle  (0) 2017.04.11
(4/500) CodeShell.kr - dummy 64  (0) 2017.04.10


어제까지 배운 지식으로 토끼모양을 출력하는 프로그램을 어셈블 언어로 작성해보자!

코드는 다음과 같다.



(어셈블 코드)




(출력 결과)



오늘은 레지스터에 대해 알아볼 것이다.

* 레지스터



1. 범용 레지스터

-> 이름이 범용이 들어가는 것 처럼 이곳저곳에서 많이 쓰이는 레지스터이다. 레지스터의 크기에 따라 명칭이 달라진다.


레지스터 크기 1, 2, 4, 8 바이트
8바이트 : RAX, RBX, RCX, RDX
4바이트 : EAX, EBX, ECX, EDX, ...
2바이트 : AX, BX, CX, ...
1바이트 : AH, AL, BH, BL, CH, CL ...


종류가 다르기보다는 크기를 나타내는 명칭이라고 생각하면된다. 같은 레지스터의 영역이다.


내용을 확인할 수 있는 프로그램을 만들면서 확인해보겠다.



(어셈블 코드)



위 코드는 레지스터 eax에 0101010101010101 이 들어간 값을 출력하는 프로그램이다.
레지스터의 내부구조를 살펴보기위해 만든 코드이다.
출력은 16진수로 표현된다. 그러므로 출력결과는 55555555 로 될것이다.



(출력 결과)



출력 결과가 55555555이 나왔다. 여기까지는 크게 다른 내용은 없다.
계산기에서 55555555을 입력하여 비트단위로 보면 0101010101010101인것을 확인 할 수 있다.



(55555555 (16))



여기서 eax 그대로에 ax를 사용하려 했으나 eax가 여기서 함수호출로 인해 사용되므로 ebx로 바꿔서 계속 진행해보겠다.
ebx 레지스터에 55555555을 넣고 bx 레지스터에 2222를 넣었다.
그리고 ebx를 출력해보면 출력결과가 어떻게 나올까?



(어셈블코드)



그 내용을 담은게 위의 코드이다.
실행해보겠다.



(실행결과)




(비트단위)



ebx 결과를 보면 ebx 내부 2바이트가 2222로 덮여쓰여진 것을 볼 수 있다.

계속해서 1바이트를 표현하는 bl, bh를 사용해보겠다. 이 둘은 상위1바이트 하위 1바이트를 가리키는 레지스터이다. ebx는 그대로 사용한 채 bh에 44 bl에 33을 넣어보겠다.



(어셈블코드)



실행하게 되면



(실행 모습)




(실행결과)




상위 1바이트는 44로 표현이 되었고 하위 1바이트는 33으로 표현되었다.

이렇게 범용레지스터는 크기를 나타내는 용어가 다르다. 즉 1바이트를 사용하고싶거나 2바이트, 4바이트 이렇게 사용하고 싶은 크기에 따라 다른 레지스터를 사용하면 된다.

2. 포인터 레지스터
 - 주소를 표현하는 레지스터이다. 이 레지스터는 용도가 분명하게 있다.
 - 용도가 정확하게 정해져 있기 때문에 다른용도로쓰면 세그먼트 폴트등 오류가 난다.



1) 스택 메모리에서 사용되는 레지스터
 - EBP ( Extended Base Pointer )
 - ESP ( Extended Stack Pointer )
 - EIP ( Extended Instruction Pointer ) : 다음 명령을 가리키는 주소


2) 문자열 복사등에 사용되는 레지스터
 - ESI ( Extended Source Index )
 - EDI ( Extended Destination Index )
-> 다른용도로 쓰이기도한다.. 중요성이 덜해서 다른용도로 쓰기도한다.
 
3) 플래그 레지스터
 - EFLAGS
 0: CF (Carry Flag ) : 올림수가 발생한 경우 비트가 1로 셋팅된다.
 6 :ZF ( Zero Flag ) : 연산의 결과가 0인 경우 비트가 1로 셋팅된다.
 7 : SF ( Sign Flag ) : 부호가 발생한 경우(음수) 비트가 1로 셋팅된다.
 11 : OF ( Overflow Flag ) : 오버플로우가 발생한 경우 비트가 1로 셋팅된다.
-> 나중에 디버거에서 직접 확인해보겠다.




6번째로 푼 문제이다!
사실 이 사이트를 시작하려고 한 이유가 처음 이사이트에 들어와서 아무문제를 클릭한 문제 중 이 문제였는데 엄청 재밌어 보여서 가입하고 풀기 시작했다.!

자바스크립트 우회인줄 알았지만 생각외로 간단하게 풀렸다. :)



(flee button 문제)



문제 시작전 ' 난 저걸 잡을수없어요!' 라고 귀여운?멘트가 나온다.



(문제 스타트)




(문제 페이지)



문제 페이지를 보면 클릭미가 나오고 마우스를 가져가 클릭하려고 해도 저 버튼이
막 날라댕긴다... 클릭을 못한다 ㅜㅜ

관리자 도구를 열어서 확인해보니.. 헉...
스크립트가 난독화 되어있다. 풀면 쉽게 풀 수 있을 듯 보였지만 그보다 내 눈에 가장 먼저 들어온 것은...



(소스코드)



위 빨간색 표시이다..!
클릭미를 누르면 key변수에 ca3e를 담아서 전송한다??

그건 나도 할 수 있는데??
실제로 해보니



(문제 해결)



flag가 실제로 나왔다..!ㅎㅎ

나의 호기심을 자극했던 문제



'WarGame > 500 Project' 카테고리의 다른 글

(8/500) Wargame.kr - fly me to the moon  (0) 2017.04.13
(7/500) Wargame.kr - WTF_CODE  (0) 2017.04.12
(5/500) Wargame.kr - QR Code Puzzle  (0) 2017.04.11
(4/500) CodeShell.kr - dummy 64  (0) 2017.04.10
(3/500) Solve Me - Winter Sleep  (0) 2017.04.06


5번째 푼 문제이다!

QR Code Puzzle이라는 재밌는 이름의 문제이다.



(QR Code Puzzle 문제)



문제 페이지는 다음과 같다.



(문제 페이지)



퍼즐을 클릭하면 실제 옛날에 많이 가지고 놀던 퍼즐처럼 조각이 움직인다.
요리 조리 움직여서 QR 코드를 완성하는건가?.. 싶었지만

개발자 도구에 들어가서 확인해보니 QR코드 원본 이미지가 따로있었다.! (물론 원본 이미지가 있을거란 생각을 하긴했었다.)



(발견)



이 사진을 열어보면



(QR코드 등장)



나는 폰으로 QR코드를 입력하였다.. ㅎㅎ



(폰으로 확인한 모습)



flag가 나온다!


'WarGame > 500 Project' 카테고리의 다른 글

(7/500) Wargame.kr - WTF_CODE  (0) 2017.04.12
(6/500) Wargame.kr - flee button  (0) 2017.04.11
(4/500) CodeShell.kr - dummy 64  (0) 2017.04.10
(3/500) Solve Me - Winter Sleep  (0) 2017.04.06
(2/500) Solve Me - Bad Compare  (0) 2017.04.06


저번에 Hello World를 출력하는 코드가 프로그램으로 번역되는
컴파일 과정을 살펴보았다.

오늘은 번역된 결과인 어셈블 언어를 공부를 시작해볼 것이다.
저번에 만들었던 코드를 조금 수정해서 printf에 넘겨주는 함수 인자를 2개로 만들어보았다.



(함수 인자 2개)




(출력 모습)



프로그램이 동작하는 결과는 같다.

다만 이 프로그램을 어셈블언어로 살펴보면



(인자 전달)



PUSH 두개가 보이고 그 후에 call이 나온다.
먼저 간단히 설명하자면 PUSH로 스택에 전달할 인자 2개를 넣어 둔 후
함수를 호출하면서 함수에 인자를 전달한다. 바로 이게 함수에 인자를 전달하는 방법 중 하나이다.

* 함수에 인자를 전달하는 방법
1. 스택 메모리를 통한 전달
이 방법을 통해 어셈블언어로 직접 구현해보겠다.



(어셈블언어)



여기서 extern은 C언어에서도 사용하는 키워드로 외부의 함수를 이용하기 위해 사용하는 것이고
우리는 printf 를 사용하기 위해 extern으로 알려주었다.
그 다음으로 segment로 data 영역과 text 영역이 보인다. text 영역에는 코드를 작성하고 data 영역에는 우리가 사용할 문자열을 저장해두었다.
함수에 전달하는 값은 순서가 반대로 입력이 된다. 스택구조는 제일 먼저 들어온 것이 가장 나중에 나오는 자료구조의 특징때문이다.

이 어셈블 코드를 목적파일로 만들고 링크작업까지 끝내고 objdump로 살펴보면 다음과 같이 확인할 수 있다.



(objdump 모습)



우리가 입력해준 데이터 msg1, msg2의 값의 주소값으로 들어간 것을 확인 할 수 있다.
여기서 msg1, 2 는 우리가 레이블이라고 표현하는데 주소값을 컴파일 전에는 알 수 없으므로 네이밍 해준 것이다.

이번에는 printf에 인자를 3개 줘보겠다. 먼저 C코드에서의 모습이다.



(C코드 모습)



이러한 코드를 어셈블언어로 작성하면?



(어셈블언어)



위와 같다. 스택구조로써 PUSH 하는 순서는 반대로 넣어주고 함수를 call 하면 된다.

실행 화면을 확인해보면 다음과 같다.



(실행 화면)



실행 화면을 보면 기존의 출력과 똑같이 나오는 것을 확인 할 수 있다.
또 objdump로 다시 살펴보면



(objdump)



3개의 인자로 넘겨주려고 했던 것들이 PUSH 되고 함수가 call 되는 것을 확인 할 수 있다.

2. 레지스터를 통한 인자 전달
두번째 방법으로는 레지스터를 통해 함수에 인자를 전달 할 수 있다. ( 사실 어셈블언어에서 함수라는 개념은 없지만 지금은 이해하기 쉽게 함수라 표현하였다.)

* 레지스터 - CPU가 사용하는 고속의 기억장치

1. 범용 레지스터( general register ) (순서대로 이용한다.)
1). EAX( Extended Accumulator Register )
2). EBX( Extended Base        Register )
3). ECX( Extended Counter     Register ) : 반복관련
4). EDX( Extended Data        Register ) : 보조적인 데이터 저장

-> 사실 이 용도로만 쓰지는 않는다. 범용이라 아무대서나 쓰이기도한다.


레지스터로 함수에 인자를 전달해보겠다. 우선 printf는 스택메모리를 통해 인자를 전달하도록 정해져있기 때문에 우리가 이 내용을 확인하려면 시스템 콜을 알아야한다.


* 시스템 콜 ( System Call )

-> 커널에 접근할 수 있는 인터페이스이다.

- 클래스에서 멤버에 접근하기 위한 메서드를 공개해놓은것과 비슷한 개념이다.
- 즉, 커널 자원에 접근하기 위한 함수라고 생각하면된다.


레드햇 6.2버젼에서는 /usr/src/linux-2.2.14/include/asm-i386/unistd.h 위치에 시스템콜이 정리되어있다.



(시스템콜)




약 200여가지 시스템 콜을 사용할 수 있다.

사용하는데 방법을 알아보기 위해서는
# man 2 함수이름
이런식으로 메뉴얼을 볼수 있다. 우리는 화면에 출력할 write를 살펴보겠다.



(write 시스템콜)



ssize_t write(int fd, const void *buf, size_t count);
3개의 인자가 필요하다.
정리하면 buf에 있는 내용을 count만큼 fd로 전달한다.

이 내용을 C코드로 작성해보면 다음과 같다.



(c코드)



fd 는 표준 출력인 1로 주었고 문자열을 buf에 입력하고 문자열 수 14를 count에 입력하였다.
프로그램 실행 결과는 다음과 같다.



(실행 결과)




그렇다면 이러한 시스템콜이 printf에도 쓰이지 않았을까?
-> 그렇다! 우리가 사용했던 C코드로 만든 프로그램이 사용한 시스템콜을 확인해보면 된다.

strace -> 해당 프로그램이 사용하는 시스템콜 목록을 확인할 수 있다.

ltrace -> 사용하는 라이브러리를 보여준다.


strace를 이용하여 c코드로 짠 프로그램을 실행시켜보면



(strace)



printf 가 사용된 프로그램에 write 시스템콜이 사용된 것을 확인할 수 있다.

지금까지 정리한 내용을 토대로 Hello, World!를 출력하는 프로그램을 어셈블 언어를 이용하여 작성해보겠다.


(어셈블 코드)



레지스트 eax에는 시스템콜 번호를 써준다. write의 시스템콜번호는 4번이므로 4를 입력해주었다.
그 다음으로는 인자를 차례로 적어주면된다.
ebx에는 fd의 값
ecx에는 버퍼에 담긴 내용 (여기서는 레이블을 이용해 주소값을 전달한다.)
edx에는 크기

그리고 마지막에 int는 정수형이 아니라 인터럽트를 뜻한다.
int 0x80은 시스템콜 인터럽트를 의미한다.
int 0x80  인터럽트가 걸리면 바로 eax를 참조하고 eax에 적힌 시스템콜번호를 확인하여 시스템콜을 수행하게 된다.

자! 컴파일하여 실행해보자!



(컴파일)




(실행)



잘 실행되는 것을 확인할 수 있다.

여기서 마지막에 Segementation 어쩌구 오류가 나오는데
우리가 프롤로그, 에필로그를 써주지 않아서 그렇다. 아직 우리가 공부하지 않았지만 시스템콜 중 exit를 이용하면 이 에러메세지가 안뜨게 종료시킬 수 있다.

그렇다면 exit를 추가해보자!



(exit(0) 추가)



이것도 똑같은 시스템 콜이므로
eax에 시스템 콜번호
그 다음 0으로 인자를 줄것이므로 ebx에는 0 그리고
int 0x80 으로 시스템콜 인터럽트를 걸면 된다.



(실행모습)



그렇게 되면 위와같이 실행이 정상적으로 종료된다.



4번째 풀이 문제이다!
Solveme는 몇일을 고민하게 했지만 다른문제로 실력을 더 쌓은 뒤 풀기로 기약하고..!
(내 스스로 500문제를 풀어내는것이 목표이기 때문에!)

CodeShell 이란 사이트! 이 사이트는 회원가입하는 것부터 문제가 있었지만
음.. 문제로 치기에는 양심이..! 
정식 문제로 500문제를 채울것이다!

첫 문제로 dummy64!
웹 문제이다. 포너블 문제 등은 지금 시스템 공부가 어느정도 되면 어서어서 해보고 싶다.!!



(dummy64)


문제 페이지 이다.



(문제 코드)



문제 코드를 보니! 예전에 다른 비슷한 문제를 푼 기억이 난다.
이 문제는 역으로 계산해서 flag를 찾아야 하는 것이다.!
우선 출력되는 것을 확인해보자!



(flag)



코드에 따르면 이 값은 역순으로 되어있다. 차근차근 하나씩 역으로 올라가면서 풀어주면 쉽겠구나! 생각이 들었다.

파이썬을 이용했다.



(문자열 뒤집기)



얻은 값을 Base 64로 인코딩!



(Base64 인코딩)



인코딩 후 이제 이 값이 encode 함수에 의해 처리되었으므로 
return 부분을 살펴보면 base64로 디코딩되서 bin2hex니까 나는 반대로
hex2bin 해준 후 base64로 인코딩하면 원래 data가 나온다.


(원래 data)




이제 이 data들을 XOR 연산을 해주는데
XOR 연산의 특징이 기억났다.
바로 
A ^ B = C
A ^ C = B
라는 것! 가물가물해서 다시 확인해보았다. ㅎㅎ



(14 ^ 2 = 12)


(12 ^ 2 = 14)




맞는걸 확인 할 수 있다!

값을 보면 길이가 2보다 작으면 자세히는 뭔지 모르겠지만 안되는것 같다.!
즉 2개씩 끊어서 해석해주면 된다.

2개씩 끊어서 역으로 아스키코드값을 구해낸다.



(아스키 코드)




이 값을 문자로 치환해주니 
flag가 바로 나왔다 :)


(문제 해결)




문제 해결!

'WarGame > 500 Project' 카테고리의 다른 글

(6/500) Wargame.kr - flee button  (0) 2017.04.11
(5/500) Wargame.kr - QR Code Puzzle  (0) 2017.04.11
(3/500) Solve Me - Winter Sleep  (0) 2017.04.06
(2/500) Solve Me - Bad Compare  (0) 2017.04.06
(1/500) Solve Me - Warm up  (0) 2017.04.06


시스템 공부에 들어서면서
바이너리 분석에 들어가 볼 것이다.

* 바이너리(실행파일)란?
 - 우리가 흔히 보는 윈도우즈의 .exe 확장자의 실행파일이라고 생각하면 된다.
 - 0과 1로 되어있는 기계어로 번역되있는 파일이다.

이 바이너리분석을 하기 위해서는 실행 파일이 어떻게 만들어지는지 공부할 필요가 있다.
즉,
다시말하면
프로그래밍된 코드가 어떻게 기계어로 번역되는지 이런 과정을 크게 Compile이라고 한다.
이 Compile 과정에 대해 알아보겠다.
우리는 C언어로 작성된 코드가 실행파일이 되는 과정을 살펴볼 것이다.

먼저! 간단하게 C코드를 작성한다. 



(sample.c 작성)



* gcc는 확장자를 보기 때문에 파일 이름 뒤에 .c를 붙여줘야한다.

만든 후 gcc를 이용해 컴파일을 해볼 것이다. gcc는 GNU C Compiler의 약자로 리눅스에서 제공하는 컴파일러이다.
아래처럼 컴파일 해본다.



(컴파일)



컴파일 완료되면 위와 같이 실행파일이 생성된것을 확인 해 볼 수 있다.
또 이 실행파일을 실행시키면 우리가 작성한 대로 Hello World 문구가 나오는 것을 확인 할 수 있다.

이 실행파일은 바이너리로 되어있기 때문에 vi 편집기 혹은 cat으로 볼 수 없고
헥스값을 볼 수 있는 xxd 데몬을 이용해서 볼 수 있다.



(바이너리 파일)



* gcc 뒤에 -o 옵션을 주어 우리가 원하는 파일이름으로 컴파일하여 실행파일을 만들 수 있다.



(-o 옵션)



* gcc 뒤에 -v 옵션을 주면 컴파일 과정이 화면에 그대로 출력된다.
우리는 gcc -v 옵션을 주어 컴파일이 이루어지는 과정을 그대로 살펴볼 것이다.



(-v 옵션)



위 화면을 보면 컴파일 과정이 주르르륵 나온 것을 볼 수 있다.
하나하나 과정을 짚어가며 살펴보겠다.

* 컴파일 과정

(1) 전처리 과정 : 컴파일 중 가장 먼저 이뤄지는 작업으로 매크로, #include 문장 해석을 한다.
전처리 : precompile


출력 화면에 해당하는 문구

 /usr/lib/gcc-lib/i386-redhat-linux/egcs-2.91.66/cpp -lang-c -v -undef -D__GNUC__=2 -D__GNUC_MINOR__=91 -D__ELF__ -Dunix -Di386 -D__i386__ -Dlinux -D__ELF__ -D__unix__ -D__i386__ -D__i386__ -D__linux__ -D__unix -D__i386 -D__linux -Asystem(posix) -Asystem(unix) -Acpu(i386) -Amachine(i386) -Di386 -D__i386 -D__i386__ -D__tune_i386__ sample.c /tmp/ccmsu4yd.i



cpp -> 전처리기이다. 즉 cpp명령이 보이고 뒤에 -어쩌구들 해서 많은 옵션들이 보인다. 뒤에


sample.c /tmp/ccmsu4yd.i 이 보이는데 sample.c를 임시디렉터리에 .i파일을 만드는 과정이다.


하지만 /tmp 디렉토리에 들어가면 .i 파일을 확인할 수 없는데 그 이유는 컴파일이 끝나면 삭제시키기 때문이다. 우리는 이 파일들을 보면서 확인할 것이므로 이러한 파일들이 삭제되지 않는 추가적인 옵션을 주어야한다.

-save-temps 옵션을 주어 임시파일 .i 파일을 삭제 하지 않게 하겠다.



(-save-temps 옵션)



옵션을 추가하니 여러 부산(?)물들 파일이 생긴것을 확인 할 수 있다.

우리가 먼저 확인해볼 것은 sample.i (전처리 과정에서 생기는 파일) 이다.!



(sample.i 파일)



큰 변화가 없어보인다?...

전처리 과정에서 어떤 일이 일어나는지 직접 눈으로 확인해보기 위해 c코드를 조금 수정해보겠다.!
define문장을 추가해보자!



(define 문장 추가)




다시 컴파일 하겠다!




(재컴파일)



재컴파일 후
sample.i 파일을 확인해본다.



(sample.i 파일)



- define 문장이 사라지고 소스코드 안에 썻던 define이 100(우리가 설정했던 값)
으로 모두 치환되어 있는 것을 확인 할 수 있다.
-> 바로 이게 전처리기의 역할이다.

2. 어셈블 과정 : 전처리된 파일을 어셈블리 형태로 변환

해당 문구

 /usr/lib/gcc-lib/i386-redhat-linux/egcs-2.91.66/cc1 /tmp/ccmsu4yd.i -quiet -dumpbase sample.c -version -o /tmp/cc0q9vPg.s


.i 파일을 .s 파일로 바꿔준다. 이때 어셈블(기계어)형태로 바꿔준다.

왜 기계어라고 해도 무관하냐면 어셈블언어와 기계어가 1:1로 매칭되기 때문에 어셈블언어를 기계어라고도 한다. 즉 바이너리로 바꾸기 직전의 파일 .s 파일을 만들어준다.



(sample.s 파일)



sample.s 파일을 확인해보면 어셈블 언어로 바뀐것을 확인할 수 있다.

3. 컴파일 과정 : 어셈블 파일을 기계어(숫자)로 번역하는 과정이다. 정확히말하면 컴파일 과정은 이부분이지만 크게 말해 이 모든 과정을 컴파일이라고 통상적으로 말하곤 한다.

해당문구

as -V -Qy -o /tmp/ccs3N70j.o /tmp/cc0q9vPg.s


as : 어셈블러를 뜻한다. 즉 as 명령으로 -o옵션으로 .s파일을 .o 파일로 만든다.
.o 파일 (기계어로 뽑아낸 파일, 오브젝트 파일)



(sample.o 파일)



파일을 보면 이제부터는 vi 편집기로 볼 수 없다. 이제부터는 바이너리이기 때문에 xxd 혹은 objdump 등 바이너리를 다루는 도구를 통해 봐야한다. objdump를 이용해 확인해보겠다.



(sample.o 파일 확인)



파일을 보면 .s 파일에서 봤던 어셈블 언어가 모두 바이너리로 바뀐것을 확인 할 수 있다.

4. 링크 단계 : 완벽한 실행파일을 생성한다. 이 때 필요한 라이브러리를 모두 합친다.

해당 문구

 /usr/lib/gcc-lib/i386-redhat-linux/egcs-2.91.66/collect2 -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 /usr/lib/crt1.o /usr/lib/crti.o /usr/lib/gcc-lib/i386-redhat-linux/egcs-2.91.66/crtbegin.o -L/usr/lib/gcc-lib/i386-redhat-linux/egcs-2.91.66 -L/usr/i386-redhat-linux/lib /tmp/ccs3N70j.o -lgcc -lc -lgcc /usr/lib/gcc-lib/i386-redhat-linux/egcs-2.91.66/crtend.o /usr/lib/crtn.o


: 오브젝트 파일과 라이브러리 오브젝트를 전부 합쳐서 하나의 실행파일로 만든다.



(a.out 파일 확인)




그렇다면 a.out 파일을 확인해보겠다.




(a.out 바이너리)



파일을 보면 왼쪽에는 메모리 주소인데 파일내용에서 해당 내용을 찾으려면(보통 파일구조 그대로 메모리로 올라가기 때문에) 대략 뒤 3자리를 참조하면된다. (항상 그런것은 아니다.)
확인해보면 3d0의 위치를 보자 



(3d0 위치)



3d0 위치에 우리가 확인했던 바이너리 문자를 볼 수 있다.

* 어셈블 언어로 코드를 작성해보고 컴파일 해보자!
Hellow World 를 출력하는 실행파일을 만들것이다. :)
nasm을 이용할 것이다! 그러기위해 .asm 확장자로 작성한다.



(sample.asm 파일 작성)




(sample.asm 내용)



컴파일 과정에서 어셈블 언어로 바꾸는 과정까지 우리가 직접 한 셈이다.
그러니 그 후 나머지 작업만 해주면 된다.

먼저 오브젝트 파일을 생성해야한다.(바이너리로 바꿔준 파일)
nasm을 이용하여 -f옵션 파일 타입 elf 로 명시한 후 sample.asm을 입력한다.



(sample.o 파일 생성)



그 후 우리가 printf 함수를 사용했으므로 이 함수의 라이브러리를 연결해주어야한다.
바로 링크단계이다.
여기서는 간단하게 static으로 구현해 볼것이다.



(링크 작업)



링크 작업이 끝나면 실행파일이 만들어지게 된다.



(실행파일)



실행 파일이 만들어진 것을 확인 할 수 있고
실행되는 것 또한 확인 할 수 있었다.



System 해킹을 공부하기에 앞서
실습환경을 구성해본다.

구성할 리눅스 버젼은 Red Hat 6.2 버젼으로 아주아주아주아주 오래된 버젼이다.
간단한 버젼으로 시스템에 입문할 것이다.

Red Hat은 오래된 리눅스이기도 하고 부팅에 문제가 있을 수 있다.
그래서 부팅할 때 맨 처음에 linux-up 이라고 입력을 해주면 된다.




(부팅 요령)



그 후 호스트 이름을 바꿔 줄 것이다.



(/etc/sysconfig/networ)




호스트 이름을 TFA로 바꿔주었다.



(호스트 이름 변경)




그 후 원격 쉘을 이용하여 공부할 것인데 연결이 가능하도록 만들어 줄것이다.
지금 설치된 Red Hat에 PAM 설정이 되어있기 때문에 몇가지 설정 파일을 수정해주어야 한다.

먼저 /etc/securetty에서 원격 터미널을 넣어주어야한다.




(/etc/securetty 설정 파일)




(pts 추가)



pts 는 원격 터미널로 8개 까지 채워준다.

그 후 pam.d 디렉토리에서 login 설정 파일을 수정해 줄 것이다.



(/etc/pam.d/login)




(pam_securetty.so 주석)




맨 윗줄을 주석처리해준다.

그 후 Xshell 에서 원격으로 로그인 할 수 있었다.



(원격 접속)




그 후 기본적으로 Red Hat에 있는 어셈블러가 아닌
인텔 기반의 어셈블러로 공부하기 위해 따로 nasm을 설치 해주었다.



(nasm 다운로드)




그 후 설치해준다!



(설치1)




(설치2)



설치 후 nasm cp 명령으로 /usr/bin 에 복사해준다.
이유는 PATH 경로에 넣기 위해서이다. 어디서든 nasm 명령어로 사용할 것이기 때문이다.



(cp)




그 후 nasm 명령어를 입력하면 명령어로 입력되는 모습을 볼 수 있다.



(설치 완료)




이로써 시스템 공부할 실습환경을 만들었다.





3번째로 풀이할 문제이다.

Solve me 의 Winter Sleep 문제이다.
이 문제를 풀면서 느낀것이 문제이름 잘지었네~ 라는 생각이 들었다. :)



(Winter Sleep)



아래는 문제 페이지이다.



(문제 페이지)



코드를 보면 단순하다. time이라는 변수에 값을 넣어 get방식으로 전달하면 된다.

그 값이 특정값 이상 이하이어야하고
그 값동안 sleep 한 후 flag를 보여준다.
음 그렇군! 초를 계산해볼까?

php online interpreter를 이용하여 계산하였다.



(sleep 할 시간 계산)



오? 간단한데? 저 값을 보내주었다.





(7776000 값 전달)




...






...


...


음? 기네?
초단위니까 몇분기다려야되는거지?






(시간 단위)



시간단위로 2160...
2160 시간.. 날짜로는 90일..
뭔가 잘못되어가는 기분이 들었다.

그럼 최소 시간으로 잡아보자! 라는 생각으로 계산해보았지만...



(최소)





(최소 시간)




(최소 60일)




이쯤 되니 아! 60일 정도 자고 일어나면 되겠다 라는 생각이 들었다.

말도 안되는 소리같고..
이쯤되서 별것들에 눈길을 주었다.
is_numeric 함수
error_reporting 함수

게다가 왜 sleep 앞에 int로 형변환을 해주었을까?
구지? is_numeric으로 숫자인지 검사해놓고서는..




(의심 대상)



오류 리포팅을 하지 않겠다? 라는 의미로 저 구문이 있었다.

sleep 에서 에러를 유발시켜서 sleep을 패스시키고 flag를 확인하는 건가?

그렇기 위해서는 우선 is_numeric을 우회할 수 있어야 했다.

그래서 php.net 공식 홈페이지에서 is_numeric을 찾아보았다.



(is_numeric)




여기서 눈에 딱 들어온건 바로
e
지수표현도 is_numeric에서 true로 판단한다는 것이었다.

이때 아하!
하고 모든것이 퍼즐처럼 맞춰졌다.

바로 그렇기 때문에 sleep 앞에 int로 형변환해주었고
e 지수표현으로 소수로 넘겨주어 int로 바뀌면 소수점들은 날라가니까 
기다릴만한 시간이 되는 거였다.

그리하야
time에 5.184e6  을 넘겨주고 flag를 얻을 수 있었다.




(문제 해결)



(문제 해결)


'WarGame > 500 Project' 카테고리의 다른 글

(6/500) Wargame.kr - flee button  (0) 2017.04.11
(5/500) Wargame.kr - QR Code Puzzle  (0) 2017.04.11
(4/500) CodeShell.kr - dummy 64  (0) 2017.04.10
(2/500) Solve Me - Bad Compare  (0) 2017.04.06
(1/500) Solve Me - Warm up  (0) 2017.04.06

+ Recent posts