1.     개인 블로그 운영

2.     개인 프로젝트 너의 타자소리가 들려

3.     팀 프로젝트 다함께 끝말잇기

4.     Hackerschool FTZ 풀기

5.     리버싱 리버싱 핵심원리

6.     CCE 참가

7.     Anti – Cheat 연구

8.   영어점수 UP!!ㅎㅅㅎ

 


1.     개인 블로그 운영

동아리 활동을 시작한 후 동아리에서 배우고 공부하는 내용과 스스로 공부한 내용을 어떻게 정리하면 좋을지 고민하다가 개인 블로그를 운영하게 되었다. 공부한 내용과 라이트 업을 주기적으로 올렸다. 블로그에 공부했던 내용을 기록하니 시간이 흐른 후에 정확한 개념이 기억나지 않을 때 내가 공부했던 내용을 다시 복습할 수 있어서 실력향상에 많은 도움이 되었다. 또한 무엇을 얼마나 공부했는지 목차로 알 수 있어서 동기부여가 되었다.


2.     개인 프로젝트 - <너의 타자 소리가 들려>

동아리 활동을 시작한 후 내가 처음부터 끝까지 개발한 가장 첫 번째 프로그램이었다. 그동안 공부했던 C언어의 지식을 정리하고자 만들었던 프로그램이었다. 처음에는 어떻게 설계를 해야 할지 막막했지만 종이로 구조도를 그려가며 생각을 정리했다. C언어를 기반으로 구조체, 파일 입출력, 동적 할당을 사용하여 내가 배웠던 프로그래밍 문법들이 실제로 어떻게 쓰이고 더 효율적으로 코드를 짜는 방법들을 연구하고 배울 수 있어서 좋은 경험이었다.


3.     팀 프로젝트 - <다 함께 끝말잇기>

버전 제어를 위한 웹 기반 호스팅 서비스인 GitHub을 사용하는 방법을 배우려고 팀 프로젝트를 시작하게 되었다. 이미 한번 프로그램을 만든 경험이 있었지만, 팀 프로젝트는 팀원과 분업을 하여 더 큰 규모의 프로그램을 만들 수 있었다. 프로젝트 도중 친구들과 분업을 하고 이견을 조율하는데 많은 어려움이 있었지만 대화를 하며 극복했다. GitHub에 코드를 올리고 공유하는 방법이 처음에는 어려웠지만 점점 익숙해졌고 자신이 수정한 코드의 기록이 남아 개발에 더 도움이 되었다. <다 함께 끝말잇기> 2명 이상의 사용자가 같은 서버에 접속하여 끝말잇기를 플레이 할 수 있는 게임 프로그램이었는데 나는 소켓 통신을 맡았다. 프로그램 개발 경험이 있었기 때문에 소켓이라는 새로운 분야를 공부하고 싶어서 도전하였다. 소켓의 개념과 소켓을 설정하는 방법 등 처음에는 이해가 잘 안 되었지만, 선배들의 도움과 정보 검색으로 소켓을 완전히 이해할 수 있게 되었다.


4.     Hackerschool 풀기

리눅스에 익숙해지고 gdb, Vm 명령어에 익숙해지기 위해 해커스쿨의 FTZ trainer 를 풀었다. 리눅스 명령어와 구조에 대해 아무것도 모른 채로 초보자를 위한 trainer 레벨을 풀기 시작했다. Trainer 9 까지 있는 연습용 ftz로 리눅스 명령어와 구조를 배우고 Level 1~Level 20까지 본격적으로 리눅스의 취약점을 이용한 해킹 시뮬레이션을 학습했다. 정해준 목표를 힌트만 보고 처음부터 끝까지 풀어간다는 것이 처음에는 어렵고 오랜 시간이 걸려 힘들었지만 점점 정보 검색에 익숙해지고 게임처럼 즐기게 되면서 간접적으로나마 해킹을 시뮬레이션해볼 수 있어서 좋은 기회였다.


5.     리버싱 - <리버싱 핵심 원리>

FTZ Level 10에 접어들고 스택의 구조와 어셈블리의 이해가 필요해서 해킹을 처음 시작할 때부터공부하고 싶었던 Reversing을 공부하기 시작했다. <리버싱 핵심 원리> 책을 읽으면서 책에 있는 예제를 풀면서 공부했다. 엄청나게 두꺼운 책을 보고 걱정이 앞섰지만 두꺼운 책을 세 부분으로 나누어 가장 기본이 되는 첫 번째 부분을 반복 학습 하였다. 처음에는 어떤 명령어인지도 모르고 OllyDbg의 사용이 너무나 어려웠지만 점점 활용에 능숙해 지면서 리버싱이 재미있어졌다. 프로그램의 결과나 중간 부분을 내가 직접 조작하고 이끌어 낼 수 있는 것이 리버싱의 가장 큰 매력으로 다가왔다. 아직 기초적인 것들을 배우고 계속 복습하고 있지만 더욱 열심히 공부하여 CTF에서 리버싱 문제를 푸는 것이 목표이다.


6.     CCE 참가

외부 연구회에서 만난 친구들과 팀을 이뤄 2017 10월에 개최된 CCE에 참가하였다. 경험을 쌓는 차원에서 참가했는데 보통 CTF에서 나오는 문제와 유형이 많이 달라서 신기했다. CCE는 설정된 환경, 프로그램이 있으면 리얼 월드(현실세계)에서 분석을 하고 공격을 하는 것을 시뮬레이션 하면서 문제를 해결해 나가는 방식이어서 해킹을 하는 기술보다 리버싱에 대한 전반적인 기초와 개념의 이해가 중요한 것 같다고 느꼈다. 아직 경험과 실력이 부족하여 본선에 진출하지는 못했지만 내년에 다시 참가하여 본선에 진출하고 싶다.

 

7.     Anti-Cheat 연구

1학년 학기 초부터 관심이 있었던 Anti-Cheat 연구를 시작하게 되었다. Anti-Cheat는 게임을 Cheating하는 행위를 역으로 공격하여 보안을 강화하는 기술이다. Cheatengine을 사용하여 체력, 총알 수, 위치, 시점등을 관리하는 메모리 주소를 찾아내서 코드를 조작했다. 지금은 메모리를 조작하는 정도의 실력이지만 계속 연구하여 직접 게임 핵을 만들어보고 이 경험을 기반으로 게임 핵을 방지하고 공격하는 Anti-Cheat 프로그램을 개발하고싶다.

 

8. 영어점수 up!!

원래 영어 점수가 70점 대였는데 열심히 공부했더니 2학기 중간부터 오르기 시작해서 기말에 드디어 96.3점이 되었습니다~~(빠ㅏ빠밤)

내년에는 영어 점수 유지하면서 수학도 올려야지ㅎㅅㅎ



동아리 활동 소감:

선린인터넷고등학교에 입학하고 나서 처음으로 시작한 동아리 활동이어서 어떤 수업을 하고, 프로젝트를 준비할지 많은 기대가 되었다. 프로그래밍과 해킹의 기초가 되는 C언어를 1학기 동안 공부하고 2학기부터는 자신이 공부하고 싶은 분야를 골라 선배들의 도움을 받으며 공부했다. 그 과정에서 개인프로젝트와 팀 프로젝트를 준비했는데 난생 처음 해보았던 프로젝트에서 많은 것들을 배웠다. 정해진 기한까지 과제를 제출하기위해 노력하고 어떤 주제로 프로그램을 만들지, 또한 완성도를 높이기 위해 많은 노력과 시간을 투자했다. 개인프로젝트 이름인 <너의 타자소리가 들려>는 파일입출력을 주로 하는 타자 검정 프로그램인데 프로젝트를 준비하면서 파일입출력을 다루는 방법을 완전히 익혔다. 팀 프로젝트는 소켓 통신을 활용한 <다함께 끝말잇기> 프로그램을 만들었는데 나는 기본적인 프로그램 로직과 클라이언트와 서버간 통신을 담당하는 소켓 프로그래밍을 담당했다. 소켓프로그래밍도 일반 C언어 프로그래밍과 크게 다르지 않아 신기하기도 했고 쓰레드의 사용법 또한 배워서 후에 많은 도움이 될것 같다. 팀 프로젝트를 하면서 팀원들과 각자 역할을 정하고 주어진 역할에 충실하면서 책임감있게 역할을 수행하였고 팀원들간에 의견을 조율하고 조합하는 방법도 배웠다. 2학년이 되면서 나도 내가 관심있는 게임 해킹 분야를 더 공부하면서 프로젝트를 진행할 예정인데 1학년때 동아리에서 경험한 많은 경험들이 좋은 참고가 될 것 같다.


                                                        나름대로 열심히 산 2018년!!(?)


'@C언어 : Layer7' 카테고리의 다른 글

PLT,GOT와 동적 라이브러리  (0) 2018.10.23
HackerSchool FTZ 풀이  (0) 2018.06.15
Git 사용 보고서  (1) 2018.06.08
너의 타자소리가 들려  (0) 2018.05.23
구조체 예제  (0) 2018.05.15

PLT(Procedure Linkage Table) : 외부 프로시저를 연결해주는 테이블. PLT를 통해 다른 라이브러리에 있는 프로시저를 호출해 사용할 수 있다

GOT(Global Offset Table) : PLT가 참조하는 테이블. 프로시저들의 주소가 들어있다


PLT와 GOT를 사용하는 이유 | Linker

어떤 코드(printf)가 쓰여있는 소스파일을 실행파일로 만들기 위해서는 컴파일이라는 과정을 거쳐야 한다. 컴파일을 통해 오브젝트 파일이 생성된다. 하지만 오브젝트 파일을그 자체로 실행하지 못하고 오브젝트 파일과 printf의 실행 코드를 찾아서 서로 연결시켜야 한다. 이런 오브젝트 파일들이 모여있는 곳을 라이브러리(Library)라고 한다. 이렇게 라이브러리 등 필요한 오브젝트 파이들을 연결시키는 작업을 Linking이라고 한다.

Link를 하는 방법에는 Static과 Dynamic이 있다.

Static Link 방식은 파일 생성시 라이브러리 내용을 포함한 실행파일을 만든다.

실행 파일 안에 모든 코드가 포함되기 때문에 라이브러리 연동 과정이 따로 필요 없고, 한번 생성한 파일에 대해서 필요한 라이브러리를 따로 관리하지 않아도 되기 때문에 편하지만 파일 크키가 커지는 단점이 있다. 또한 동일한 라이브러리를 사용하더라도 해당 라이브러리를 사용하는 모든 프로그래들은 라이브러리의 내용을 메모리에 매핑 시켜야 한다

Dynamic Link 방식은 공유라이브러리를 사용한다. 라이브러리를 하나의 메모리 공간에 매핑하고 여러 프로그램에서 공유하여 사용하는 것이다.

실행파일 안에 라이브러리 코드를 포함하지 않기 때문에 파일 크기도 작아지고 실행시 적은 메모리를 차지한다. 그러나 실행파일이 라이브러리에 의존하기 때문에 라이브러리가 없으면 실행할 수 없다.


PLT와 GOT는 Dynamic Link 방식으로 컴파일 했을때 사용되는데 그 이유는 라이브러리가 프로그램 외부에 있기 때문에 함수의 주소를 알아오는 과정이 필요하기 때문이다.


Dynamic Link 방식으로 프로그램이 만들어지면 함수를 호출 할 때 PLT를 참조하게 된다. PLT는 GOT로 점프를 하고 GOT에는 라이브러에 존재하는 실제 함수의 주소가 쓰여있어서 printf 함수를 호출하게 된다. 

여기서 첫 호출인지 아닌지에 따라 동작 과정이 조금 달라진다.

첫 번째 호출이라면 GOT에 실제 함수의 주소가 쓰여있지 않고 두번째 호출부터 GOT에 실제 함수의 주소가 쓰인다. 그래서 첫 호출 시에는 Linker가 dl_resolve라는 함수를 사용해 필요한 함수의 주소를 알아오고, GOT에 그 주소를 써준 후 해당 함수를 호출한다.


라이브러리란? | 라이브러니는 다른 프로그램들과 링크되기 위하여 존재하는 하나 이상의 서브루틴이나 함수들의 집합 파일 형태를 말한다. 보통 미리 컴파일된 형태인 오브젝트코드 형태로 존재한다. 라이브러리라는 기술이 생긴 이유는 코드의 재사용, 부품화 실현, 소스를 제공하지 않음으로서 중요 기술의 유출 방지, 개발자들의 개발시간 단축들의 장점이 있기 때문이다. 

라이브러리들은 사용자의 프로그램과 링크되어, 실행이 가능한 완전한 프로그램을 이룬다. 링크의 종류는 Static Link가 있고 Dynamic Link가 있다.


공유 라이브러리(.so/.sa) | 공유라이브러리를 사용하여 컴파일을 하면 링커가 실행 파일에다가 "실행될 때 우선 이 라이브러리를 로딩시킬 것"이라는 표시를 해둔다. 그리고 실행할 때 라이브러리에 있는 컴파일된 코드를 가져와 사용한다.

이렇게 하면 정적 라이브러리를 사용하는 것보다 파일 크기가 작아지고, 메모리를 적게 차지하고 메모리 사용에 효율적이다. 그러니 배포할 때 공유 라이브러리를 함께 배포해야 한다. 


공유 라이브러리 구성 | 공유 라이브러리 파일은 확장자가 파일포맷이 ELF이면 .so, a.out이면 .sa이다. (a.out은 과거 유닉스 계통 운영 체제에서 사용하던 실행 파일과 목적 파일 형식)

그리고 그 뒤에 버전 숫자가 붙는데 메이지 넘버와 마이너 넘버이다.(메이지 넘버는 라이브러리 버전들 간 잠재적 비호환성을 나타내고, 마이너 넘버는 버그 픽스들만을 나타낸다) 

Example ) 일반적으로 libexample.so 파일은 libexample.so.N에 링크되고 다시 이것은 libexample.so.N.M에 링크됨. N은 가장 높은 메이저 넘버이고, M은 가장 높은 마이너 넘버이다.


출처 : http://sens.tistory.com/33

        https://bpsecblog.wordpress.com/2016/03/07/about_got_plt_1/

'@C언어 : Layer7' 카테고리의 다른 글

2018년에 한것..(?)  (0) 2018.12.24
HackerSchool FTZ 풀이  (0) 2018.06.15
Git 사용 보고서  (1) 2018.06.08
너의 타자소리가 들려  (0) 2018.05.23
구조체 예제  (0) 2018.05.15


level 1


level 1의 비밀번호는 level1

우선 정보를 모으기 위해 ls -al을 해 보았더니 hint라는 파일이 있어서 cat명령어를 사용하여 출력해보았다.




이렇게 힌트가 떴다. setuid라고?

Set 이란 말은 "변경하다" 란 뜻을 가지고 있고, UID는 User ID의 약자이다.

설명하면 SetUID는 일시적으로 자신의 ID를 변경하는 것을 말한다.


자신의 암호를 변경하는 passwd 파일에 루트 권한의 SetUID가 걸려있어서

일반 사용자들이 그 passwd 파일을 실행하는 동안에는 "루트로의 일시적인 아이디 변경" 이 되는것이다.




SetUID가 걸린 파일을 찾는 명령어는

find / -user level2 -perm -4000 2> /dev/null 이다. 


2> /dev/null : 오류는 /dev/null 파일에 담으라는 뜻


/bin/ExcuteMe 라는 이름의 파일이 떠서 실행시켜보면



my-pass 는 현재 자신의 비밀번호를 볼 수 있는 명령어 이고

chmod는 디렉토리나 파일의 권한을 바꿔주는 명령어 이다.

아무런 제한이 없다면 저 두 명령어를 쓰는것이 젤 쉽겠지만 안된다고 하니 다른 방법을 찾아보자.


내가 약간 희한하게 푼 것같기는 한데 /etc/passwd 에 사용자의 비밀번호가 기록되어 있다고해서 찾아봤더니

많은 것들 중 level2의 쉘이 /bin/bash인 걸 알 수 있다.

그래서 level2의 권한으로 명령어를 하나 실행할 수 있을때 /bin/bash를 사용해서 level 2의 쉘을 열기로 했고

level2의 쉘을 따게 되었당!!!



level 2


level 2의 비밀번호는 hacker or cracker


hint에서는 텍스트 파일 도중 쉘 명령어를 실행 시킬 수 있다고 해서



 일단 level3의 setuid를 가진 파일을 찾아봤다.

find / -user level3 -perm -4000 2> /dev/null 명령어를 쳤더니 

/usr/bin/editor가 떠서 실행시켜 보았더니 vim파일이었다.




구글에서 파일 편집 도중 명령어를 사용하려면 !를 붙이고 실행시켜야 한다고 했다.

level3:x:3003:3003:Level 3:/home/level3:/bin/bash 

level3 또한 쉘의 종류가 bash여서 :! /bin/bash라고 했더니 level3을 들어가졌다.

/usr/bin/editor가 level3의 setuid를 갖고 있는 파일이었기 때문에 level3의 권한으로 level3의 쉘이 들어갈 수 있었다.


level3


level 3의 비밀번호는 can you fly?


힌트에는 autodig의 소스와 more hints 로 

1)동시에 여러 명령어를 사용하려면?

2) 문자열 형태로 명령어를 전달하려면?

이 있었다.

문제를 풀기 전에 저 more hints에 대한것을 찾아봤는데


- 동시에 여러 명령어를 사용하려면?

    ; - 앞의 명령어가 실패해도 다음 명령어가 실행

    && - 앞의 명령어가 성공했을 때 다음 명령어가 실행

    & - 앞의 명령어를 백그라운드로 돌리고 동시에 뒤의 명령어를 실행


- 문자열 형태로 명령어를 전달하려면?

쉘 스크립트 : 쉘 명령어가 담긴 파일

"asdf asdf" <-이렇게


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
 
int main(int argc, char **argv){
 
    char cmd[100];
 
    if( argc!=2 ){
        printf"Auto Digger Version 0.9\n" );
        printf"Usage : %s host\n", argv[0] );
        exit(0);
    }
 
    strcpy( cmd, "dig @" );
    strcat( cmd, argv[1] );
    strcat( cmd, " version.bind chaos txt");
 
    system( cmd );
 
 
cs


argc : 명령어 개수를 받는 변수
argv : 명령어 문자열을 저장하는 변수
이 소스의 핵심은 argv[1]로 넘어온 사용자가 적은 명령을 바로 실행시키는 것이다.

autodig라고해서 구글에 dig를 검색해 보았더니
dig는 Domain Information Groper의 약자로 네임서버로 부터 정보를 가져올 수 있는 툴이다.

dig 명령은 DNS 네임서버 구성과 도메인 설정이 완료된 후, 일반 사용자의 입장에서 설정한 도메인네임에 대한 DNS 질의응답이 정상적으로 이루어지는지를 확인 점검하는 경우에 많이 사용한다고 한다.

[root@web ~]# dig [@server] [domain] [query type]

server : 확인하고자할 네임서버를 지정하는 곳이며 지정하지 않을경우 리눅스 
/etc/resolv.conf에 등록된 네임서버를 이용하여 루트 서버를 조회하게 됩니다.
라고 해서 /etc/resolv.conf에 들어갔더니 192.168.203.2가 나왔는데 솔직히 이건 필요없고
 


이 문제의 핵심은 소스를해석해서 argv[1]로 넘어온 사용자가 적은 명령을 바로 실행시킨다는것.[system( cmd );]
그래서 이 문제를 해결하는 방법이 총 3개 있다.
1. /bin/autodig "192.168.203.2 && /bin/bash ;" 



2. /bin/autodig "192.168.203.2 && /bin/bash &&"


3. autodig의 소스를 복사해서 ./test라는 파일을 만들어서 "192.168.203.2 && /bin/bash"했더니 저렇게 나온다. 저 소스가 결과적으로 실행하는 명령어를 출력하게 만들어 놓음. /bin/bash는 뒤에 인자가 붙지 않으면 쉘을 실행시키고 뒤에 인자가 붙으면 그 파일을 쉘 스크립트로 실행한다. 그래서 저 뒤에 붙는 version.bind을 쉘스크립트로 만들어서 /bin/bash를 실행시키게 한다. 1번과 2번은 version.bind가 실행되지 않도록 /bin/bash까지만 실행하도록 만들어 놓은 것 이다.

<소스를 복사해서 실제로 소스가하는 일은 무엇인지 알아보았다.> 
[level3@ftz tmp]$ ./test "192.168.203.2 && /bin/bash"
===================
dig @192.168.203.2 && /bin/bash version.bind chaos txt
===================
[level3@ftz tmp]$ /bin/autodig "192.168.203.2 && /bin/bash"

























'@C언어 : Layer7' 카테고리의 다른 글

2018년에 한것..(?)  (0) 2018.12.24
PLT,GOT와 동적 라이브러리  (0) 2018.10.23
Git 사용 보고서  (1) 2018.06.08
너의 타자소리가 들려  (0) 2018.05.23
구조체 예제  (0) 2018.05.15

Git 이란?

VCS(version Control System)로 버전 관리 시스템이다.


Git을 쓰는 이유

1. 여러 개발자들과 같이 작업을 할때 코드를 유용하게 공유 할 수 있다.

2. 변경된 내용이나 오류를 업데이트 하거나 수정하기 쉽다.

3. 변경된 내용이 왜 변경되었는지 기록이 가능하다.


Branch 란?

브랜치란 독립적으로 어떤 작업을 진행하기 위한 개념이다.

각각의 독립적인 브랜치는 다른 브랜치의 영향을 받지 않기 때문에 여러 작업을 동시에 진행할 수 있다.

이런 브랜치들이 다른 브랜치들과 병합함으로써 모든 작업내용을 갖고있는 하나의 브랜치로도 만들 수 있다.


Git 사용법>


<git에 올릴 파일 생성 & git에 파일 올리기>


poodoong@layer7:~$ git init  : git을 사용할 수 있도록 초기화

Initialized empty Git repository in /home/poodoong/.git/


poodoong@layer7:~$ ls -al   :  모든 파일 보기

total 44

drwxr-xr-x  5 poodoong poodoong 4096  6월  7 23:31 .

drwxr-xr-x 44 root     root     4096  6월  7 21:32 ..

-rw-------  1 poodoong poodoong  313  6월  5 23:07 .bash_history

-rw-r--r--  1 poodoong poodoong  220  6월  4 19:27 .bash_logout

-rw-r--r--  1 poodoong poodoong 3771  6월  4 19:27 .bashrc

drwx------  2 poodoong poodoong 4096  6월  4 19:29 .cache

drwxrwxr-x  7 poodoong poodoong 4096  6월  7 23:31 .git

-rw-r--r--  1 poodoong poodoong 2181  6월  4 19:27 .kshrc

-rw-r--r--  1 poodoong poodoong  655  6월  4 19:27 .profile

-rw-------  1 poodoong poodoong  940  6월  5 20:46 .viminfo

drwxrwxr-x  3 poodoong poodoong 4096  6월  5 20:46 test


poodoong@layer7:~$ ls  : 모든 디렉토리 보기

test


poodoong@layer7:~/test$ vim README.c  : test디렉토리에 README라는 c언어 파일 만들기


poodoong@layer7:~/test$ gcc -o README README.c  : 컴파일 돌리기(만약 아무 에러가 없다면 아무것도 출력되지 않음)


poodoong@layer7:~/test$ git config --global user.email "kimwhayoung0115@naver.com"  : git 사용자 설정
poodoong@layer7:~/test$ git config --global user.name "Glume.f" 

poodoong@layer7:~/test$ git add * : 파일 추가하기

poodoong@layer7:~/test$ git commit -m "Initial Commit"  : 기록 저장(분기점 생성)
[master (root-commit) 5875b2a] Initial Commit
 5 files changed, 12 insertions(+)
 create mode 100755 README
 create mode 100644 README.c
 create mode 100644 README.md
 create mode 100644 Yogroot.c
 create mode 100755 mainaa

poodoong@layer7:~/test$ git push origin master --force  :  서버에 올리기(--force는 강제로 덮어쓰기)
Username for 'https://github.com': kimwhayoung0115@naver.com
Password for 'https://kimwhayoung0115@naver.com@github.com':



<git에 올린 파일 지우기>

poodoong@layer7:~/test$ ls -l  : 현재 test 디렉토리에 있는 파일 모두 출력
total 36
-rwxrwxr-x 1 poodoong poodoong 8608  6월  7 23:40 README
-rw-rw-r-- 1 poodoong poodoong   72  6월  7 23:39 README.c
-rw-rw-r-- 1 poodoong poodoong   13  6월  4 19:36 README.md
-rw-rw-r-- 1 poodoong poodoong   71  6월  5 20:46 Yogroot.c
-rwxrwxr-x 1 poodoong poodoong 8608  6월  5 20:46 mainaa

poodoong@layer7:~/test$ rm mainaa  : mainaa 삭제
poodoong@layer7:~/test$ git add mainaa : mainaa을 삭제했다는 것을 git한테 직접 알림

poodoong@layer7:~/test$ rm README README.md Yogroot.c  : 필요 없는 것들을 더 삭제해 본다

poodoong@layer7:~/test$ git add * : (오류) add * 은 현재 존재하는 파일만 git 기록에 추가하기 때문에 삭제된 디렉토리의 정보를 올리려면 git add -A를 써야한다. mainaa를 삭제하고 add *를 썼음에도 불구하고 잘 삭제되었던 이유는 우리가 git한테 직접 삭제사실을 알렸기 때문

poodoong@layer7:~/test$ git commit -m "remove file"  : 파일 삭제 이유를 알리고 기록에 추가
[master 266939b] remove file
 1 file changed, 0 insertions(+), 0 deletions(-)
 delete mode 100755 mainaa

poodoong@layer7:~/test$ git add -A : 이 명령어는 모든 파일의 변경된 이력을 기록에 추가

poodoong@layer7:~/test$ git commit -m "remove file"
[master e1d1253] remove file
 3 files changed, 6 deletions(-)
 delete mode 100755 README
 delete mode 100644 README.md
 delete mode 100644 Yogroot.c

poodoong@layer7:~/test$ git push origin master : 서버에 올리기
Username for 'https://github.com': kimwhayoung0115@naver.com
Password for 'https://kimwhayoung0115@naver.com@github.com': 

삭제하지 않은 README.c 파일만 남은 것을 확인 할 수 있다.







'@C언어 : Layer7' 카테고리의 다른 글

PLT,GOT와 동적 라이브러리  (0) 2018.10.23
HackerSchool FTZ 풀이  (0) 2018.06.15
너의 타자소리가 들려  (0) 2018.05.23
구조체 예제  (0) 2018.05.15
구조체  (0) 2018.05.13


너의 타자소리가 들려 - by 화영


1. 작품 개요


-개발동기

평소 영어 타자 실력이 좋지 못해서 컴퓨터에 기본적으로 깔려있는 한컴 타자연습에 들어가서  연습을 하려고 했더니 프로그램이 오류가 나면서 작동이 중지 됐었다. C언어 프로젝트의 주제를 고민하다가 이 기회를 이용하여 직접 타자연습 프로그램을 만들게 되었다.


-개발환경

visual studio 2017


-제작과정

키보드 연습, 긴글 연습을 먼저 만들고 시작하면을 디자인 했다.

17~19일에 키보드 연습을 만들었고 , 

19~22일을 긴글 연습을 만드는데 사용했다.

나머지는 오류를 수정하고 기능추가와 보고서와 ppt를 만들었다.


2. 작품 소개


-사용 헤더 및 라이브러리


#include<stdio.h>

#include<stdlib.h>

#include<time.h>

#include<windows.h>


#define _CRT_SECURE_NO_WARNINGS

#define COLOR_YELLOW SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 14)

#define COLOR_WHITE SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7)


1) 시간 측정을 위해 time.h 라이브러리 사용

2) 글자 색 변환을 위해 windows.h 라이브러리 사용

3) SetConsoleTextAttribute(GetStdHandle

(STD_OUTPUT_HANDLE), 14) 글자를 노란색으로 변환

4) #define COLOR_WHITE SetConsoleTextAttribute(GetStdHandle

(STD_OUTPUT_HANDLE), 7) 글자를 흰색으로 변환



-사용자 지정 함수


void start(); ->시작 화면 출력


void level_one();  //키보드

void print_keyboard(char key); ->키보드 랜덤 출력

char random_key(); ->랜덤숫자 지정

int input_key(char key, int *arr); ->입력받는 함수

void keyboard_turn(int *arr); ->키보드를 출력하고 출력횟수 제한


void level_two();  //긴글

char *ReadAllFile(char *fileName); ->파일을 읽고 버퍼에 저장

void Input_filename(char *Inbuf, int len); ->파일 이름 입력 확인

void print_contents(GameInfo Game); ->지정 길이 만큼 내용 출력

void input_contents(GameInfo *Game); ->출력된 내용 입력받기

void print_score(GameInfo Game); ->타수와 정확도 측정.출력


-구조체


typedef struct _Engfile {      

char file_Letitgo[30];

char file_Partof[30];

char file_Awolenew[30];

char file_Healthe[30];

char file_Sugar[30];

}Engfile;

->긴글 연습에 필요한 파일 이름을 저장시켜놓은 구조체

(입력받은 파일이름을 비교하기 위해)


typedef struct _Gameinfo {
char *contents; //내용 들어있는 contents 포인터
int offset; //contents에서 입력할 글자 가리키기
int start_time; //입력 시작 시간
//현재속도 = (타수-백스페이스*2) / 경과시간(초) * 60초
//      한컴타자는 백스페이스 * 3
int end_time; //입력 끝난 시간
int elapsedTime; // 입력 끝난 시간 - 입력 시작 시간
int correct; //입력 글자 중 맞은 개수
int wrong; //입력 글자중 틀린 개수
}GameInfo;
->긴글 연습 한번을 실행 시킬때 필요한 내용을 담아놓은 구조체



-실행 화면


<시작화면>




<키보드 연습(1)>



<키보드 연습(2)>



<긴 글 연습(1)>



<긴 글 연습(2)>



3. 개발하면서 느낀점


내가 목표한 프로그램을 다 만들었다는 거에 큰 성취감을 느꼈고 지금까지 배워왔던 모든 C언어 지식들을 총 동원하여 만들어서 다시한번 명령어들의 쓰임새와 알고있던 것들이 정리되는 느낌이었다.

'@C언어 : Layer7' 카테고리의 다른 글

HackerSchool FTZ 풀이  (0) 2018.06.15
Git 사용 보고서  (1) 2018.06.08
구조체 예제  (0) 2018.05.15
구조체  (0) 2018.05.13
메모리 구조  (0) 2018.05.12

<구조체 예제>

세 명의 정보를 입력받아 출력


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#define _CRT_SECURE_NO_WARNINGS
 
#include<stdio.h>
#include<stdlib.h>
 
typedef struct student {
    int num;
    char name[10];
    char tell[15];
    int age, money;
}Student;
 
int main() {
    Student s1[3];
 
    for (int i = 0; i < 3; i++) {
        printf("번호 입력 :");
        scanf("%d"&s1[i].num);
        printf("이름 입력 :");
        scanf("%9s", s1[i].name);
        printf("전화번호 입력 :");
        scanf("%14s", s1[i].tell);
        printf("나이 입력 :");
        scanf("%d"&s1[i].age);
        printf("연봉 입력 :");
        scanf("%d"&s1[i].money);
    }
    
    printf("번호 \t 이름 \t 전화번호 \t 나이 \t 연봉\n");
    for (int i = 0; i < 3; i++) {
        printf("%d \t %s \t %s \t %d \t %d\n", s1[i].num,
 s1[i].name, s1[i].tell, s1[i].age,s1[i].money);
    }
    system("pause");
    return 0;
}
cs


'@C언어 : Layer7' 카테고리의 다른 글

Git 사용 보고서  (1) 2018.06.08
너의 타자소리가 들려  (0) 2018.05.23
구조체  (0) 2018.05.13
메모리 구조  (0) 2018.05.12
Codeup 100제  (0) 2018.04.13


구조체


구조체란 ?

구조체는 배열보다 발전된 개념으로 변수의 종류에 관계없이 '서로 관련된 데이터를 하나로 묶어 놓은 것'이다.


학생정보를 입력받는 배열을 만든다면 하나의 배열에 모두 담는다면 좋겠지만 학생의 이름은 int에 저장할 수 없으므로 따로 선언할 수 밖에 없다.


char name[10];   //이름

int score[4];       //학번, 국어 점수, 수학 점수, 영어 점수


그러나 구조체를 사용하면 이러한 문제를 해결할 수 있다.


struct student {        //구조체 student를 정의

int no;                     //학번

char name[10];         //이름

int kor, math, eng;    //과목별 점수

} ;


위의 코드는 student라는 이름의 구조체를 정의한 것으로, 학생의 여러 정보를 하나의 구조체로 묶었다.

구조체의 정의는 구조체의 구성요소에 대한 정보일 뿐 구조체를 정의한다고 저장공간이 생기는 것은 아니다.


struct student s1 ; // 구조체 변수 s1을 선언


위와 같이 구조체 변수를 선언해야 저장공간이 생기고 구조체 안에 선언된 순서대로 연속적인 저장공간이 마련된다.


int 형 4개 + char 형 10개 + 패딩 2 바이트  =  28 바이트


패딩이란 ?

시스템의  '정렬 제한'에 의해 구조체의 멤버 사이에 빈 공간이 생긴 것

모든 변수는 주소가 4의 배수인 곳에만 저장되도록 배치한다는 것이다.

 

구조체 정의와 선언


정의


struct 구조체이름{    //구조체 student를 정의

타입 멤버 이름;   //구조체의 멤버

타입 멤버 이름;

...

} ;   <-중괄호 뒤에 ' ; '를 붙여야 함


이 구조체의 정의는 새로운 타입을 정의한 것일 뿐, 아직 값을 저장할 공간이 마련되지 않았다.


선언

 구조체를 정의하면 struct '구조체 이름' 라는 타입이 새로 추가되고 구조체 타입의 변수를 선언하는 것은 기존의 변수 선언 방법과 다르지 않다.


예)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
typedef struct student {
    int no;
    char name[10];
    int kor, math, eng;
}Student;
 
int main() {
    Student s1 = { 1,"KIM",100,100,100 };
 
    printf("%d %s %d %d %d\n", s1.no, s1.name,
 s1.kor, s1.math, s1.eng);
    system("pause");
    return 0;
}
cs



1
2
3
4
5
typedef struct student {
    int no;
    char name[10];
    int kor, math, eng;
}Student;
cs






구조체 타입의 변수를 선언할 때 매번 struct를 붙이는 것이 불편할땐
typedef로 새롭게 정의할 수 있다. typedef struct student Student ; //struct student를 Student로 정의 Student s1 ; //struct student s1; 과 동일

구조체의 초기화

선언된 구조체 변수의 저장공간에 접근하려면 '구조체 변수이름. 멤버이름'의

형식을 사용해야 한다.

1

2

3

4

5

6

7

int main() {

    Student s1 = { 1,"KIM",100,100,100 };

 

    printf("%d %s %d %d %d\n", s1.no, s1.name, s1.kor, s1.math, s1.eng);

    system("pause");

    return 0;

}

Colored by Color Scripter

cs

구조체의 멤버에 접근할 때 사용하는 ' . '는 '멤버 접근 연산자'또는 간단히 '멤버 연산자'라고 한다.


struct student s1={ 1, "KLIDONG", 100,100,100} ;  

//구조체 변수를 선언과 동시에 조기화


struct student s1 = { 0 } ; 

//구조체 변수의 모든 멤버를 0으로 초기화




구조체의 중첩


구조체도 구조체의 멤버가될 수 있으며, 이렇게 하는 것을 구조체의 중이라고 한다.


 

1
2
3
4
5
6
typedef struct userScore {
    char uerId[8];         //사용자 id
     int score,rank;        //점수
    int iyear, imon, iday; //입력날짜
    int cyear, cmon, cday; //변경 날짜
}Userscore;
cs
4,5번째 줄을 보면 입력날짜와 변경날짜를 따로따로 입력해줘야 하는데 이것을 또하나의 구조체로 만들어 중첩시킨다면


1
2
3
4
5
6
7
8
9
10
struct date {
    int year, mon, day;
};
 
typedef struct userScore {
    char uerId[8];         //사용자 id
     int score,rank;        //점수
    struct date inputDate; //입력날짜
    struct date changeDate; //변경 날짜
}Userscore;
cs


이렇게 구조체 userScore가 더 간결해졌고, 코드의 중복이 제거되어 수정도 쉬워졌다. 또한 구조체 date는 다른 구조체를 작성할때도 재사용될 수 있을 것이다. 또한 구조체 자신을 중첩하는 것은 허용되지 않는다. 


중첩된 구조체의 멤버에 접근하려면 ' . '연산자를 한번 더 사용해야한다.

s1. inputDate. year   = 2016;

s1. inputDate.mon    = 1;

s1. inputDate.day     = 6;


중첩된 구조체 변수의 선언과 초기화를 함께 할 때는 다음과 같이 괄호를 중첩한다. 

s1=userScore s1 = {"myId",100 ,1 , { 2016, 1, 31 },{ 2016 , 2, 2 }};





구조체의 배열

같은 타입의 구조체 변수들을 하나로 묶어서 배열로 선언할 수 있다.

배열 요소의 타입 구조체라는 것만 제외하면 일반 배열과 다르지 않으므로 그동안 배열을 다뤄왔던 것과 똑같이 하면 된다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
typedef struct student {
    int no;
    char name[10];
    int kor, math, eng;
}Student;    
 
int main() {
    Student stuArr[] = {
        {1,"KIM",100,100,10},
        {2,"LEE",90,90,90},
        {3,"CHOI",80,80,80},
        {4,"PARK",100,100,100}
    };
    return 0;
}
cs


int no ,char name[10] ,int kor ,math, eng를 멤버로 갖고있는 구조체 Student형인 배열 stuArr를 4개 선언하고 선언과 동시에 초기화 시켰다. 구조체 배열을 초기화 하는 것은 2차원 배열을 초기화 하는 것과 동일하다.



구조체의 포인터

구조체 변수 역시 포인터로 다룰 수 있으며, 다루는 방법은 같다.

struct student s = { 1, "홍길동", 100, 100, 100 } ;

struct student *p = &s ; //구조체 변수 s의 주소를 포인터 p에 저장


포인터로 구조체의 멤버에 접근할 때는 '*'연산자와 '.'연산자를 같이 사용한다.

포인터로 구조체의 멤버에 접근하려면, 두개의 연산자에 괄호까지 더해야 해서 불편하다. 그래서 제공되는 연산자가 '->'이다.

'->'포인터가 가리키는 구조체의 멤버에 저장된 값을 반환한다.

                            

     s . kor = 90 ;                                 

                              (*p). kor = 90 ;

                              p -> kor = 90 ;



구조체의 배열의 포인터


구조체 배열을가리키는 포인터의 타입은 구조체의 타입에 '*'을 붙인 것이다.

struct student stuArr[4];

struct student *pArr = stuArr;







'@C언어 : Layer7' 카테고리의 다른 글

너의 타자소리가 들려  (0) 2018.05.23
구조체 예제  (0) 2018.05.15
메모리 구조  (0) 2018.05.12
Codeup 100제  (0) 2018.04.13
문자열 함수 구현  (0) 2018.04.11

메모리 구조


프로그램이 실행되면, 프로세스가 된다. OS는 프로세스가 작업을 수행하는데 사용할 수 있는 메모리를 제공한다. 메모리의 저장 공간은 세분화하여 5가지 영역으로 나뉘어져 있다.



1. 코드 영역(Code segment)

프로그램을 실행하면, 프로그램 파일( .exe)의 내용이 여기에 저장된다. 이 영역에 저장된 내용을 변경할 수 없고, 읽기만 가능하다. 나머지 영역들은 읽기와 쓰기가 모두 가능하다.




2. 데이터 영역(Data segment)

전역 변수와 정적 변수(static)가 할당되는 영역이다. 초기화된 전역변수는 Data영역에 할당되고 초기화 되지 않은 전역변수는 BSS에 할당되어 0으로 초기화 된다.




3. BSS 영역(Block Stated Symbol)

초기화 되지 않은 전역변수가 할당되어 0으로 초기화 된다.


1
2
3
4
5
6
7
8
9
#include<stdio.h>
int a = 3//Data 영역
int b; //BSS영역
int main() {
 
    int c; //Stack 영역
    printf("%d %d %d\n", a, b, c); // 3 0 쓰레기 값 
    return 0;
}
cs


int a = 3//Data 영역
int b; //BSS영역
int c; //Stack 영역



4. Stack 영역

함수가 작업을 수행하는데 사용하는 메모리 공간이다. 함수가 호출되면 스택에 호출된 함수를 위한 메모리가 할당되며, 이 메모리는 함수가 작업을 수행하는 동안 지역 변수를 저장하는데 사용된다.

그리고 함수가 작업을 마치면 할당되었던 메모리는 반환되어 해당 함수의 지역변수는 자동으로 메모리에서 제거된다.



5. Heap 영역

프로그램 실행 중에 동적으로 메모리를 할당받아 사용할 수 있는 영역이다. 필요할 때 할당 받아서 사용하고, 다 사용한 후에는 반환 할 수 있다. 힙은 스택과 달리 자동으로 메모리가 반환되지 않으므로, 동적할당 받은 메모리는 사용 후에 반드시 메모리를 반환하는 함수를 호출해야 한다.



5-1. 동적할당

함수 내에 지역적으로 선언된 변수나 배열은 합수가 종료되면 메모리에서 사라지기 때문에 여러 함수에서 사용하기에 부적합 하다. 그렇다고 전역적으로 선언된 변수나 배열은 여러 함수에서 사용하기 좋지만 프로그램이 종료될때까지 메모리를 점유해서 메모리 공간을 비효율 적으로 사용하게 된다. 필요할 때만 메모리를 할당받아 사용하기 위한 방법이 바로 동적할당이다.


동적 메모리 할당 : 실행 중에 원하는 기간 동안 필요한 만큼의 메모리를 할당받는 것


malloc( ) 

동적으로 메모리를 할당 받으려면 malloc( ) 이라는 함수를 사용해야 하는데  이 함수를 호출하면 메모리 할당 요청이 OS에게 전달된다. 그러면 OS는 힙(heap)에서 사용중이지 않은 영역을 찾아 할당해준다. 할당 받은 메모리는 사용한 후에 free( )를 호출해서 반환한다.


사용법은 이러하다.

1
2
3
4
5
6
7
8
9
10
11
12
#include<stdio.h>
#include<stdlib.h>
int main() {
    //동적 할당받은 공간의 주소를 포인터 pi에 저장
    int* pi = (int*)malloc(sizeof(int)); 
    //동적 할당받은 공간에 값을 저장
    *pi = 10;
    //동적 할당받은 공간에 저장된 값을 출력
    printf("%d\n"*pi);
free(pi);
    system("pause");
    return 0;
}
cs

동적으로 할당받은 저장공간은 오직 포인터를 통해서만 접근할 수 있다.

ex)   *(p+0) = 1;

       *p = 1;

  p[0] = 1;

위 세줄은 모두 같은 의미이다.



malloc( )의 반환값은 타입이 'void*' 이므로, 이 값을 어떠한 타입의 포인터에 저장해도 된다. = 할당 받은 공간을 어떠한 용도로든 자유롭게 사용할 수 있다.

동적으로 할당받은 공간은 주로 배열로 쓰인다. 그리고 이 공간을 배열로 사용하는 것은 배열을 포인터로 다루는 것과 완전히 동일하다. 



memset 

힙도 스택처럼 초기화 없이 덮어쓰기만 하므로 malloc( )을 통해 할당받은 메모리는 이전 데이터 값(쓰레기 값)이 그대로 남아있다. 초기화가 필요하면, memset로 초기화 할 수있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main() {
    //동적 할당받은 공간의 주소를 포인터 pi에 저장
    int* pi = (int*)malloc(sizeof(int)); 
    //동적 할당받은 공간을 0으로 초기화
    memset(pi, 0sizeof(int));
    //동적 할당받은 공간에 초기화된 값을 출력
    printf("%d\n"*pi);
free(pi);
    system("pause");
    return 0;
}
fㄹcs




free( ) 

동적으로 할당받은 메모리는 사용한 후에 반드시 할당을 해제해야 한다. 그렇지 않으면 메모리 누수가 발생한다. 또한 free( )를 한 후에 해당 메모리에 접근하는 댕글링 포인터를 조심해야한다.


*메모리 누수 : 프로그램에 메모리를 할당 후, 해제하지 않아서 시스템의 메모리를 고갈시키는 소프트웨어 오류

*댕글링 포인터 : 해제된 메모리를 가리키는 포인터


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main() {
    //동적 할당받은 공간의 주소를 포인터 pi에 저장
    int* pi = (int*)malloc(sizeof(int)); 
    //동적 할당받은 공간을 0으로 초기화
    memset(pi, 0sizeof(int));
    //동적 할당받은 공간에 초기화된 값을 출력
    printf("%d\n"*pi);
    //동적 할당받은 공간의 사용이 다하면 메모리를 해제
    free(pi);
    system("pause");
    return 0;
}
cs



calloc( ) 

calloc( )은 다음과 같이 정의 되어 있다.

void *calloc(size_t n , size_t size) ;


calloc은 매개변수가 2개 이다. 타입의 크기와 개수를 따로 받는다.


iArr = malloc(100 * sizeof(int));

iArr = calloc(100, sizeof(int));


위의 두 문장은 모두 int타입의 값을 100개 저장할 수 있는 메모리를 할당받는다.

(malloc 과 calloc의 차이점은 calloc은 malloc과 다르게 할당받은 메모리는 모두 0으로 자동 초기화 된다)



realloc( ) 


동적 할당받은 메모리가 부족하게 된 경우에는 추가로 malloc을 사용할 수도 있지만 두 메모리의 주소가 연속적이라는 보장이 없기 때문에 사용하는데 어려움이 있다. 그래서 이럴땐 realloc( )을 사용하면 된다.


realloc은 다음과 같이 정의 되어 있다.

void *realloc(void *memblock, size_t newSize) ;


첫 번째 매개변수 :동적 할당받은 메모리의 주소

두 번째 매개변수 :변경하고자 하는 메모리의 크기

첫 번째 매개변수의 값이 NULL이면 malloc과 같은 역할을

두 번째 매개변수의 값이 0이면 free( )처럼 동작하여 해당 메모리는 해제된다. 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main() {
    int* Arr;
    Arr = (int*)malloc(sizeof(int* 10);
    *(Arr + 5= 10;
    printf("%d %d\n",Arr[5],Arr[15]);
    //동적할당된 Arr의 크기가 10이어서 10을 넘으면 쓰레기 값이 출력된다.
    Arr = (int*)realloc(Arr, sizeof(int* 10 * 2);
    //기존의 동적할당 되었던 Arr의 크기를 2배로 늘리고 값을 할당하였다.
    Arr[15= 10;
    printf("%d  %d\n"*(Arr+5),Arr[15]);
    system("pause");
    return 0;
}
cs


'@C언어 : Layer7' 카테고리의 다른 글

구조체 예제  (0) 2018.05.15
구조체  (0) 2018.05.13
Codeup 100제  (0) 2018.04.13
문자열 함수 구현  (0) 2018.04.11
함수 문제풀이  (0) 2018.04.09

+ Recent posts