반응형

BFS를 통해 푸는 문제이다. 물론 DFS로 문제를 풀 수 있을 것 같다.


나는 세가지 변수를 설정했다.


1. 1촌 관계를 저장하는 배열 : Arr[][2]


2. 방문했던 점을 저장하는 배열 : visited[]


3. 얼마만큼 지나왔는지 저장하는 배열 : total[]


세가지만 이용하면 쉽게 문제를 풀 수 있다.


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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import java.io.FileInputStream;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
 
public class Main {
    static int[][] arr;
    static boolean[] visited;
    static int[] total;
    static int x;
    static int y;
 
    public static void main(String[] args) throws Exception {
        // TODO Auto-generated method stub
        Scanner sc = new Scanner(new FileInputStream("input.txt"));
        int N = sc.nextInt();
        arr = new int[N + 1][2];    //1촌관계를 저장할 배열
        visited = new boolean[N + 1];    // 방문했던 값을 다시 방문하면 무한루프에 빠지게 된다.
        total = new int[N + 1];        //몇칸을 거쳐왔는지에 대한 배열
        x = sc.nextInt();        //입력 X값
        y = sc.nextInt();        //입력 Y값
 
        
        int K = sc.nextInt();
        for (int i = 1; i <= K; i++) {
            arr[i][0= sc.nextInt();
            arr[i][1= sc.nextInt();
        }
        System.out.println(BFS(x, N));
    }
 
    public static int BFS(int x, int N) {
        Queue<Integer> q = new LinkedList<Integer>();
        q.add(x);
        //큐가 비었으면 연결이 끊어졌다는 소리이다.
        while (!q.isEmpty()) {
            int nextX = q.poll();
            visited[nextX] = true;
            //방문한 점은 true로 바꿈으로써 재방문 하지 안도록 한다.
            for (int i = 0; i < N; i++) {
                //전체 배열을 돌면서 연결되있으면서 방문 안한점이 있나 체크한다
                //있다면 큐에 넣어준다.
                if (arr[i][0== nextX && !visited[arr[i][1]]) {
                    //1촌관계가 랜덤으로 되어있으므로 왼쪽 라인 한번
                    q.add(arr[i][1]);
                    //이전에서 +1 된 값을 저장한다
                    total[arr[i][1]] = total[arr[i][0]] + 1;
                } else if (arr[i][1== nextX && !visited[arr[i][0]]) {
                    //오른쪽 라인 한번
                    q.add(arr[i][0]);
                    //이전에서 +1된값을 저장한다.
                    total[arr[i][0]] = total[arr[i][1]] + 1;
                }
            }
            //q가 비었거나 찾는값이 있으면 종료한다.
            if (!q.isEmpty() && q.peek() == y) {
                return total[y];
            }
 
        }
        return -1;
    }
}
 
cs


문제에 나와있지 않은 예시를 하나 들자면.

10

7 6

9

1 2

1 3

1 4

9 1

9 10

3 5

3 6

2 7

2 8

이 있다. 이때의 결과값은 4가 나와야 한다.

반응형
반응형


규칙만 찾으면 정말 금방 풀 수 있는 문제이다.


DP 문제는 일단 경우를 모두 써서 규칙을 찾아내는 게 중요하다고 배웠다.


그래서 무작정 경우를 작성해보았다.



위 표와 같은 결과가 나온다.

위 표에서 DP[] 라는 배열을 할당했을때

 - 0은 횟수(N)이 증가함에도 상관없이 1임을 알수 있었다.

 - 1~9는 횟수(N)이 1일때를 제외하고, 이전에 있던 자신의 값과 바로 전값의 합임을 알 수 있었다.

즉,  dp[i] = dp[i]  dp[i - 1] 이라는 규칙을 얻어 낼 수 있었다.


<소스코드>


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
import java.io.FileInputStream;
import java.util.Scanner;
 
public class Main {
    public static void main(String args[]) throws Exception {
        Scanner sc = new Scanner(System.in);
        //Scanner sc = new Scanner(new FileInputStream("input.txt"));
 
        int N = sc.nextInt();
 
        int[] dp = new int[10];
        int result = 0;
        for (int i = 0; i < 10; i++) {
            dp[i] = 1;
        }
        for (int i = 1; i < N; i++) {
            result = 0;
            for (int j = 1; j < 10; j++) {
                dp[j] = (dp[j] + dp[j - 1]) % 10007;
                result = (result + dp[j]) % 10007;
            }
        }
        if(result==0){
            System.out.println(10);
        }
        else
        System.out.println((result + 1) % 10007);
    }
}
 
cs


반응형
반응형

배열이 아닌 큐를 사용해서 풀었다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import java.io.FileInputStream;
import java.util.*;
 
public class Main {
 
    public static void main(String args[]) throws Exception {
        Scanner sc = new Scanner(System.in);
        //Scanner sc = new Scanner(new FileInputStream("input.txt"));
        int N = sc.nextInt();
        int M = sc.nextInt();
        Queue<Integer> q = new LinkedList<Integer>();    //Queue 사용
        int count = 0;
        for (int i = 0; i < N; i++) {
            q.add(sc.nextInt());    //큐에 저장
        }
        
        while(!q.isEmpty()&&M-q.peek()>=0){    //큐가 비었거나     합의 값이 0보다 커질경우에 종료
            M -= q.poll();
            count++;
        }
        System.out.println(count);
    }
}
 
cs


반응형
반응형

1. Sort로 풀면 안될것 (개수가 10000000개 이기 때문에 시간초과)

 -> 배열을 이용한다. (예를 들어 3번이 4번 나왔다면 arr[3]++ 를 사용하여 개수를 늘려준다.)


2. Scanner 사용을 하면 안됨 (★★★★★★★★★★★★★★★★)

-> BufferedReader ,BufferedWriter 를 사용한다.

 + bufferedwriter의 flush() 함수를 사용해도 시간 초과가 뜬다.

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
36
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
 
public class Main {
 
    public static void main(String[] args) throws Exception {
        // TODO Auto-generated method stub
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
 
        int N = Integer.parseInt(br.readLine());
        int[] arr = new int[10001];
        // 10000000 개이기 때문에 sort를 사용하면 안된다.
        for (int i = 0; i < N; i++) {
            arr[Integer.parseInt(br.readLine())] ++;
        }
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
 
        for (int i = 1; i < 10000; i++) {
            if (arr[i] > 0) { //arr[i]가 0보다 작거나 같으면 사용된 횟수가 없기 때문에 패스
                for (int j = 0; j < arr[i]; j++) {
                    //저장된 갯수만큼 출력해줘야 하기 때문에
                    bw.write(Integer.toString(i) + "\n");
                    //bw.flush(); 가끔 사용안하면 이클립스 Console에 출력이 안됨
                }
            }
        }
        br.close();
        bw.close();
    }
 
}
 
 
 
cs


반응형
반응형

1. 변경 전 사진

 

 

맨처음 CSS를 변경하지 않았을 경우의 사진입니다.

 

2. 사이드바의 ▷ 색상 변경

 

CSS 파일에서 

/*

 * sidebar

 */

로 부터 구성되어있는 부분을 찾아줍니다. (Ctrl + F를 통해 category 를 찾아도 가능)

 

찾았다면

 #sidebar .category { color : #ff0000;}

를 등록하면 바뀌게 됩니다. (#ff0000 은 빨강색)

 

3. 카테고리의 주제 색상 변경

 

본문의 주제 부분의 색상을 바꿔보겠습니다. 

그 전에 F12 를 통해 본문과 아래 것들의 html 명칭을 확인해 줍니다.

 

a.link_item으로 구성되어있는것을 볼 수 있습니다.

 

a.link_sub_item으로 구성되어있는것을 볼 수 있습니다.

 

4. 결론

#sidebar .category ul li ul li .link_item { color: #ff0000; font-weight: bold;}

를 CSS에 추가하게 되면 본문은 색상이 빨갛게 변하는 것을 볼 수있습니다.

 

아래것들의 디자인을 바꾸고 싶다면?

 

#sidebar .category ul li ul li .link_sub_item { }

를사용하게 되면 바뀌게 되겠습니다.

 

끄읏!

 

반응형
반응형
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
import sys, struct
import pefile
from pydbg import *
from pydbg.defines import *
 
def log(str):
    global fpp
    print str
    fpp.write(str)
    fpp.write("\n")
    return 
    
def addr_handler(dbg):               
    global func_name
    ret_addr = dbg.context.Eax
    if ret_addr:
        dict[ret_addr] = func_name
        dbg.bp_set(ret_addr, handler=generic)
    return DBG_CONTINUE
 
def generic(dbg):
    global func_name
    eip = dbg.context.Eip
    esp = dbg.context.Esp
    paddr = dbg.read_process_memory(esp, 4)
    addr = struct.unpack("L", paddr)[0]
    addr = int(addr)
    if addr < 70000000:
        log("RETURN ADDRESS: 0x%.8x\tCALL: %s" % (addr, dict[eip])) 
    if dict[eip] == "KERNEL32!GetProcAddress" or dict[eip] == "GetProcAddress"
        try:
            esp = dbg.context.Esp
            addr = esp + 0x8
            size = 50
            pstring = dbg.read_process_memory(addr, 4)
            pstring = struct.unpack("L", pstring)[0]
            pstring = int(pstring)
            if pstring > 500:
                data = dbg.read_process_memory(pstring, size)
                func_name = dbg.get_ascii_string(data)
            else:
                func_name = "Ordinal entry"
            paddr = dbg.read_process_memory(esp, 4)
            addr = struct.unpack("L", paddr)[0]
            addr = int(addr)
            dbg.bp_set(addr, handler=addr_handler)
        except:
            pass
    return DBG_CONTINUE
 
 
def entryhandler(dbg):
    getaddr = dbg.func_resolve("kernel32.dll""GetProcAddress")  
    dict[getaddr] = "kernel32!GetProcAddress"
    dbg.bp_set(getaddr, handler=generic)
    for entry in pe.DIRECTORY_ENTRY_IMPORT:
        DllName = entry.dll
        for imp in entry.imports:                  
            api = imp.name
            address = dbg.func_resolve(DllName, api)
            if address:
                try:
                    Dllname = DllName.split(".")[0]
                    dll_func = Dllname + "!" + api
                    dict[address] = dll_func
                    dbg.bp_set(address, handler=generic)
                except:
                    pass
    
    return DBG_CONTINUE        
 
def main():
    global pe, DllName, func_name, fpp
    global dict
    dict = {}
    file = sys.argv[1]
    fpp = open("API Calls List.txt"'a')
    pe = pefile.PE(file)
    dbg = pydbg()
    dbg.load(file)
    entrypoint = pe.OPTIONAL_HEADER.ImageBase + pe.OPTIONAL_HEADER.AddressOfEntryPoint
    dbg.bp_set(entrypoint, handler=entryhandler)
    dbg.run()
    log('\n'
    fpp.close()
 
if __name__ == '__main__':
    main()
cs


출처 : http://securityxploded.com/api-call-tracing-with-pefile-pydbg-and-idapython.php

exe 파일등의 PE file을 pydbg() 기능을 통해 API를 분석해오는 과정이다.

정확히 이해는 못했지만 IAT 테이블에 저장되어있는 API들에 hooking을 하여 실행될 때 사용되는 API들을 출력해주는 함수라고 알고 있다.

정확한 이해를 하기 위해서는 출처에 들어가서 확인해 보는 편이 좋을 듯 하다.


명령어 입력으로는 '>> python   파이썬파일.py    대상 파일.exe'   형식이다.



반응형
반응형


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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<signal.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<sys/wait.h>
#include <unistd.h>
#include <time.h>
#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#define MAXLINE 514
void z_handler();// 시그널 처리 함수
static char base64_table[] = {
    'A''B''C''D''E''F''G''H''I''J''K''L''M',
    'N''O''P''Q''R''S''T''U''V''W''X''Y''Z',
    'a''b''c''d''e''f''g''h''i''j''k''l''m',
    'n''o''p''q''r''s''t''u''v''w''x''y''z',
    '0''1''2''3''4''5''6''7''8''9''+''/''\0'
};
static char base64_pad = '=';
unsigned char *base64_encode(const unsigned char *str, int length, int *ret_length) {
    const unsigned char *current = str;
    int i = 0;
    unsigned char *result = (unsigned char *)malloc(((length + 3 - length % 3* 4 / 3 + 1* sizeof(char));
    while (length > 2) { /* keep going until we have less than 24 bits */
        result[i++= base64_table[current[0>> 2];
        result[i++= base64_table[((current[0& 0x03<< 4+ (current[1>> 4)];
        result[i++= base64_table[((current[1& 0x0f<< 2+ (current[2>> 6)];
        result[i++= base64_table[current[2& 0x3f];
        current += 3;
        length -= 3/* we just handle 3 octets of data */
    }
    /* now deal with the tail end of things */
    if (length != 0) {
        result[i++= base64_table[current[0>> 2];
        if (length > 1) {
            result[i++= base64_table[((current[0& 0x03<< 4+ (current[1>> 4)];
            result[i++= base64_table[(current[1& 0x0f<< 2];
            result[i++= base64_pad;
        }
        else {
            result[i++= base64_table[(current[0& 0x03<< 4];
            result[i++= base64_pad;
            result[i++= base64_pad;
        }
    }
    if (ret_length) {
        *ret_length = i;
    }
    result[i] = '\0';
    return result;
}
/* as above, but backwards. :) */
unsigned char *base64_decode(const unsigned char *str, int length, int *ret_length) {
    const unsigned char *current = str;
    int ch, i = 0, j = 0, k;
    /* this sucks for threaded environments */
    static short reverse_table[256];
    static int table_built;
    unsigned char *result;
    if (++table_built == 1) {
        char *chp;
        for (ch = 0; ch < 256; ch++) {
            chp = strchr(base64_table, ch);
            if (chp) {
                reverse_table[ch] = chp - base64_table;
            }
            else {
                reverse_table[ch] = -1;
            }
        }
    }
    result = (unsigned char *)malloc(length + 1);
    if (result == NULL) {
        return NULL;
    }
    /* run through the whole string, converting as we go */
    while ((ch = *current++!= '\0') {
        if (ch == base64_pad) break;
        /* When Base64 gets POSTed, all pluses are interpreted as spaces.
        This line changes them back.  It's not exactly the Base64 spec,
        but it is completely compatible with it (the spec says that
        spaces are invalid).  This will also save many people considerable
        headache.  - Turadg Aleahmad <turadg@wise.berkeley.edu>
        */
        if (ch == ' ') ch = '+';
        ch = reverse_table[ch];
        if (ch < 0continue;
        switch (i % 4) {
        case 0:
            result[j] = ch << 2;
            break;
        case 1:
            result[j++|= ch >> 4;
            result[j] = (ch & 0x0f<< 4;
            break;
        case 2:
            result[j++|= ch >> 2;
            result[j] = (ch & 0x03<< 6;
            break;
        case 3:
            result[j++|= ch;
            break;
        }
        i++;
    }
    k = j;
    /* mop things up if we ended on a boundary */
    if (ch == base64_pad) {
        switch (i % 4) {
        case 0:
        case 1:
            free(result);
            return NULL;
        case 2:
            k++;
        case 3:
            result[k++= 0;
        }
    }
    if (ret_length) {
        *ret_length = j;
    }
    result[k] = '\0';
    return result;
}
void handleErrors(void)
{
    ERR_print_errors_fp(stderr);
    abort();
}
int encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key, unsigned char *iv, unsigned char *ciphertext)
{
    EVP_CIPHER_CTX *ctx;
    int len = 0;
    int ciphertext_len;
    /* Create and initialise the context */
    if (!(ctx = EVP_CIPHER_CTX_new())) handleErrors();
    /* Initialise the encryption operation. IMPORTANT - ensure you use a key
    * and IV size appropriate for your cipher
    * In this example we are using 256 bit AES (i.e. a 256 bit key). The
    * IV size for *most* modes is the same as the block size. For AES this
    * is 128 bits */
    if (1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))
        handleErrors();
    /* Provide the message to be encrypted, and obtain the encrypted output.
    * EVP_EncryptUpdate can be called multiple times if necessary
    */
    if (1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
        handleErrors();
    ciphertext_len = len;
    /* Finalise the encryption. Further ciphertext bytes may be written at
    * this stage.
    */
    if (1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) handleErrors();
    ciphertext_len += len;
    /* Clean up */
    EVP_CIPHER_CTX_free(ctx);
    return ciphertext_len;
}
int decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key, unsigned char *iv, unsigned char *plaintext)
{
    EVP_CIPHER_CTX *ctx;
    int len;
    int plaintext_len;
    /* Create and initialise the context */
    if (!(ctx = EVP_CIPHER_CTX_new())) handleErrors();
    /* Initialise the decryption operation. IMPORTANT - ensure you use a key
    * and IV size appropriate for your cipher
    * In this example we are using 256 bit AES (i.e. a 256 bit key). The
    * IV size for *most* modes is the same as the block size. For AES this
    * is 128 bits */
    if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))
        handleErrors();
    /* Provide the message to be decrypted, and obtain the plaintext output.
    * EVP_DecryptUpdate can be called multiple times if necessary
    */
    if (1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
        handleErrors();
    plaintext_len = len;
    /* Finalise the decryption. Further plaintext bytes may be written at
    * this stage.
    */
    if (1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len)) handleErrors();
    plaintext_len += len;
    /* Clean up */
    EVP_CIPHER_CTX_free(ctx);
    return plaintext_len;
}
int main(int argc, char *argv[])
{
    /* A 256 bit key */
    unsigned char *key = (unsigned char *)"01234567890123456789012345678901";
    /* A 128 bit IV */
    unsigned char *iv = (unsigned char *)"0123456789012345";
    int server_sock;
    int client_sock;
    int clntlen;
    int num;
    int encoding_num = 0;
    int decoding_num = 1;
    char sendline[MAXLINE];
    char recvline[MAXLINE];
    char key_compare[MAXLINE];
    int size;
    pid_t fork_ret;
    struct sockaddr_in client_addr;
    struct sockaddr_in server_addr;
    int state;
    struct sigaction act;
    act.sa_handler = z_handler;
    unsigned char ciphertext[MAXLINE];
    unsigned char plaintext[MAXLINE];
    /* Buffer for the decrypted text */
    unsigned char decryptedtext[MAXLINE];
    int decryptedtext_len, ciphertext_len;
    int encryptedtext_len, plaintext_len;
    char* test2;
    char* test3;
    /* Initialise the library */
    ERR_load_crypto_strings();
    OpenSSL_add_all_algorithms();
    OPENSSL_config(NULL);
    if(argc!=2)
    {
        printf("Usage : %s PORT \n", argv[0]);
        exit(0);
    }
    // 소켓 생성
    if((server_sock = socket(PF_INET, SOCK_STREAM, 0)) <0)
    {
        printf("Server : can't open stream socket. \n");
        exit(0);
    }
    // 소켓 주소 구조체에 주소 세팅
    bzero((char *)&server_addr, sizeof(server_addr)); // 소켓 주소 구조체 초기화
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_addr.sin_port = htons(atoi(argv[1]));
    sigaction(SIGCHLD, &act, 0);
    // 소켓에 서버 주소 연결
    if(bind(server_sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
    {
        printf("Server : can't bind local address.\n");
        exit(0);
    }
    printf("Server started. \nWaiting for client.. \n");
    listen(server_sock, 1);
    // 클라이언트의 연결요청 수락
    clntlen = sizeof(client_addr);
    if((client_sock = accept(server_sock, (struct sockaddr *)&client_addr, &clntlen)) <0)
    {
        printf("Server : failed in accepting. \n");
        exit(0);
    }
    if((fork_ret = fork()) > 0)
    {
        // 부모 프로세스는 키보드 입력을 클라이언트로 송신
        while(fgets(sendline, MAXLINE, stdin)!=NULL)
        {
            sendline[strlen(sendline)] = '\0';
            size = strlen(sendline);
            printf("\n--------------  S  E  N  D  ----------------\n\n");
            printf("SEND DATA : %s\n\n",sendline);
            if(size!=0){
                ciphertext_len = encrypt(sendline, strlen(sendline), key, iv, ciphertext);
                ciphertext[ciphertext_len] = '\0';
                printf("AES256 ( SEND DATA ) : %s \n\n",ciphertext);
                test2 = base64_encode((unsigned char *)ciphertext, ciphertext_len,&encoding_num);
                printf("BASE64ENCODING ( AES256 ( SEND DATA ) ) : %s \n\n",test2);
                if(write(client_sock, test2, strlen(test2)) == size)
                {
                    printf("Error in write. \n");
                }
                //memset(sendline,0x00,MAXLINE);
                //memset(test2,0x00,MAXLINE);
                //memset(ciphertext,0x00,MAXLINE);
            }
        }
    }
    else if(fork_ret == 0)
    {
        // 자식 프로세스는 클라이언트로부터 수신된 메시지를 화면에 출력
        while(1)
        {
            memset(recvline,0x00,MAXLINE);
            if((size = read(client_sock, recvline, MAXLINE)) < 0)
            {
                printf("Error if read. \n");
                close(client_sock);
                exit(0);
            }
            //recvline[strlen(recvline)] = '\0';
            memset(plaintext,0x00,MAXLINE);
            printf("--------------  R E C E I V E  -------------\n\n");
            printf("BASE64ENCODING ( AES256 ( RECEIVE DATA ) ) : %s\n\n", recvline); // 화면 출력
            test3 = base64_decode((unsigned char *)recvline, strlen(recvline),&decoding_num);
            printf(" AES256 ( RECEIVE DATA ) : %s\n\n", test3); // 화면 출력
            plaintext_len = decrypt(test3, decoding_num, key, iv, plaintext);
            plaintext[plaintext_len] = '\0';
            printf("RECEIVE DATA : %s\n\n", plaintext); // 화면 출력
        }
    }
    close(server_sock);
    close(client_sock);
    return 0;
}
void z_handler()
{
    int state;
    waitpid(-1&state, WNOHANG);
    exit(0);
    return ;
}
cs


양방향 통신코드를 가져와서 openssl 라이브러리를 통한 AES256 암호화를 하였다.

양방향 소켓통신 출처 : http://yms2047.tistory.com/entry/%EC%96%91%EB%B0%A9%ED%96%A5-%ED%86%B5%EC%8B%A011-%EB%8C%80%ED%99%94

base 64 인코딩은 인터넷 어디선가 가져왔는데 주소가 기억나지 않는다.

base 64 인코딩은 openssl 라이브러리안에 존재한다고 한다. 그걸 사용하는것이 나을수 있어보인다.

동작화면은 아래와 같다.




반응형
반응형
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
using System;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
 
 
using System.Security.Cryptography;
using System.IO;
 
namespace AsyncTest
{
    public partial class Form1 : Form
    {
        private Socket clientSock;  /* client Socket */
        private Socket cbSock;      /* client Async Callback Socket */
        private byte[] recvBuffer;
 
        private const int MAXSIZE = 514;  /* 4096  */
        private string HOST = "xxx.xxx.xxx.xxx";
        private int PORT = 123;
        private string Enter_key;
        private string recvString;
 
        public Form1()
        {
            InitializeComponent();
            recvBuffer = new byte[MAXSIZE];
 
            this.DoInit();
        }
 
 
        //소켓 생성및 연결
        public void DoInit()
        {
            clientSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            this.BeginConnect();
        }
 
 
        /*----------------------*
        *  Connection  *
        *----------------------*/
 
        public void BeginConnect()
        {
 
            tbDebug.Text = "서버 접속 대기 중";
            try
            {
                clientSock.BeginConnect(HOST, PORT, new AsyncCallback(ConnectCallBack), clientSock);
            }
            catch (SocketException se)
            {
                /*서버 접속 실패 */
                tbDebug.Text += "\r\n서버접속 실패하였습니다. " + se.NativeErrorCode;
                this.DoInit();
 
            }
 
        }
 
        /*----------------------*
        * ##### CallBack ##### *
        *  Connection  *
        *----------------------*/
        private void ConnectCallBack(IAsyncResult IAR)
        {
            try
            {
                // 보류중인 연결을 완성
                Socket tempSock = (Socket)IAR.AsyncState;
                IPEndPoint svrEP = (IPEndPoint)tempSock.RemoteEndPoint;
 
                tbDebug.Text += "\r\n 서버로 접속 성공 : " + svrEP.Address;
 
                tempSock.EndConnect(IAR);
                cbSock = tempSock;
                cbSock.BeginReceive(this.recvBuffer, 0, recvBuffer.Length, SocketFlags.None,
                                    new AsyncCallback(OnReceiveCallBack), cbSock);
            }
            catch (SocketException se)
            {
                if (se.SocketErrorCode == SocketError.NotConnected)
                {
                    tbDebug.Text += "\r\n서버 접속 실패 CallBack " + se.Message;
                    this.BeginConnect();
                }
            }
        }
 
        /*----------------------*
         *     Send   *
         *----------------------*/
        public void BeginSend(string message)
        {
            tbDebug.Text += "\r\n\r\n--------------  S  E  N  D  ----------------";
            tbDebug.Text += "\r\n\r\nSEND DATA : " + message;
            try
            {
                /* 연결 성공시 */
                if (clientSock.Connected)
                {
                    //키보드를 통해 입력한 데이터를 암호화 한다. 뒤의 숫자는 암호화에 쓰일 key이다.
                    string chiper = AES_encrypt(message, "01234567890123456789012345678901");
                    //데이터는 byte[]로 보내야하기 때문에 string -> byte
                    byte[] buffer = Encoding.UTF8.GetBytes(chiper);
                    //데이터 전송
                    clientSock.BeginSend(buffer, 0, buffer.Length, SocketFlags.None,
                                            new AsyncCallback(SendCallBack), chiper);
                }
            }
            catch (SocketException e)
            {
                tbDebug.Text = "\r\n\r\n전송 에러 : " + e.Message;
            }
        }
 
        /*----------------------*
        * ##### CallBack ##### *
        *     Send   *
        *----------------------*/
        private void SendCallBack(IAsyncResult IAR)
        {
            string message = (string)IAR.AsyncState;
            //데이터 전송에 있어서 공백이 '\0'로 채워질수 있기 때문에 이를 방지하기위해 trim() 함수를 사용한다.
            message = message.Trim('\0');
            tbDebug.Text += "\r\n\r\nBASE64ENCODING ( AES256 ( SEND DATA ) ) : " + message;
 
        }
 
 
 
        /*----------------------*
        *    Receive   *
        *----------------------*/
        public void Receive()
        {
 
            cbSock.BeginReceive(this.recvBuffer, 0, recvBuffer.Length,
                SocketFlags.None, new AsyncCallback(OnReceiveCallBack), cbSock);
        }
 
        /*----------------------*
        * ##### CallBack ##### *
        *    Receive   *
        *----------------------*/
        private void OnReceiveCallBack(IAsyncResult IAR)
        {
            try
            {
                Socket tempSock = (Socket)IAR.AsyncState;
                int nReadSize = tempSock.EndReceive(IAR);
                if (nReadSize != 0)
                {
 
                    tbDebug.Text += "\r\n\r\n--------------  R E C E I V E  -------------";
                    //수신받은 데이터의 나머지부분이 '\0'로 채워진다.
                    //그렇게 되면 복호화가 되지않기 때문에 trim() 함수를 사용하여 제거한다.
                    recvString = Encoding.UTF8.GetString(recvBuffer).Trim('\0');
                    Array.Clear(recvBuffer, 0, recvBuffer.Length);
 
                    tbDebug.Text += "\r\n\r\nBASE64ENCODING ( AES256 ( RECEIVE DATA ) ) : " + recvString;
 
                    //복호화
                    string chiper = AES_decrypt(recvString, "01234567890123456789012345678901");
                    this.tbDebug.Text += "\r\n\r\nRECEIVE DATA : " + chiper;
 
 
                }
                this.Receive();
            }
            catch (SocketException se)
            {
                if (se.SocketErrorCode == SocketError.ConnectionReset)
                {
                    this.BeginConnect();
                }
            }
        }
 
        //AES256 암호화
        public String AES_encrypt(String Input, String key)
        {
            RijndaelManaged aes = new RijndaelManaged();
            aes.KeySize = 256;
            aes.BlockSize = 128;
            aes.Mode = CipherMode.CBC;
            aes.Padding = PaddingMode.PKCS7;
            aes.Key = Encoding.UTF8.GetBytes(key);
            aes.IV = Encoding.UTF8.GetBytes("0123456789012345");
 
            var encrypt = aes.CreateEncryptor(aes.Key, aes.IV);
            byte[] xBuff = null;
            using (var ms = new MemoryStream())
            {
                using (var cs = new CryptoStream(ms, encrypt, CryptoStreamMode.Write))
                {
                    byte[] xXml = Encoding.UTF8.GetBytes(Input);
 
                    cs.Write(xXml, 0, xXml.Length);
                }
 
                xBuff = ms.ToArray();
                string recvdata = Encoding.Default.GetString(xBuff);
                tbDebug.Text += "\r\n\r\nAES256 ( SEND DATA ) : " + recvdata;
            }
 
            string Output = Convert.ToBase64String(xBuff);
            return Output;
        }
        //AES 256 복호화
        public string AES_decrypt(string Input, string key)
        {
            RijndaelManaged aes = new RijndaelManaged();
            aes.KeySize = 256;
            aes.BlockSize = 128;
            aes.Mode = CipherMode.CBC;
            aes.Padding = PaddingMode.PKCS7;
            aes.Key = Encoding.UTF8.GetBytes(key);
            aes.IV = Encoding.UTF8.GetBytes("0123456789012345");
 
            var decrypt = aes.CreateDecryptor();
            byte[] xBuff = null;
            using (var ms = new MemoryStream())
            {
 
                using (var cs = new CryptoStream(ms, decrypt, CryptoStreamMode.Write))
                {
                    byte[] xXml = Convert.FromBase64String(Input);
                    string recvdata = Encoding.Default.GetString(xXml);
                    tbDebug.Text += "\r\n\r\nAES256 ( RECEIVE DATA ) : " + recvdata;
 
 
                    cs.Write(xXml, 0, xXml.Length);
                }
 
                xBuff = ms.ToArray();
            }
 
            string Output = Encoding.UTF8.GetString(xBuff);
            return Output;
        }
 
 
 
        private void Form1_Load(object sender, EventArgs e)
        {
        }
 
        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            Enter_key = textBox1.Text;
 
        }
 
        private void button1_Click(object sender, EventArgs e)
        {
            if (Enter_key != "")
            {
                this.BeginSend(Enter_key);
                textBox1.Text = "";
            }
        }
 
        private void textBox1_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                button1_Click(sender, e);
            }
        }
    }
}
cs


c#으로 코드가 이루어져 있으며 base64 Encoding,Decoding 과 aes256 암복호화를 통해 통신을 한다.

http://www.imcore.net/encryption-aes256-c-objectivec-ios-iphone-ipad-php-java-android-perl-javascript-python/

위에분의 블로그가 없었다면 암복호화에 엄청난 애를 먹었을 것이다.

Form안에 들어가는 내용이며 전체적인 소스코드는 올리지 않았다.

동작화면은 아래와 같다.








반응형
반응형

모든 경우의 수를 구해야 계산을 할 수있다.

예를 들어 집합의 크기가 3일 경우 

000, 001, 010, 011, 100, 101, 110, 111 의 8가지 경우의 수를 계산해서 더해야 한다.

비트 연산을 통해 모든 경우의 수를 계산했다.

비트 연산은 다시 블로그에 작성을 해야겠다.

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
36
37
38
39
40
41
42
43
44
import java.io.FileInputStream;
import java.util.Scanner;
 
public class Main {
 
    public static void main(String[] args) throws Exception {
        // TODO Auto-generated method stub
 
        Scanner sc = new Scanner(new FileInputStream("input.txt"));
        //Scanner sc1 = new Scanner(System.in);
        int n = sc.nextInt();
        int s = sc.nextInt();
        int[] arr = new int[n];
        int result = 0;
        int sum = 0;
        for (int i = 0; i < n; i++) {
            arr[i] = sc.nextInt();
        }
        //i는 0000~1111까지
        for (int i = 1; i < 1 << n; i++) {
 
            int bit = i;
            //0000 을 
            //bit!=0 은 도중에 할게 없으면 컷 0000111 일떄 1뽑고 난후 0이므로 돌 필요가 없다.
            for (int j = 0; bit != 0; j++, bit >>= 1) {
 
 
                //첫번째 자리가 0이면 j는 구할필요가 없다. ex) 10010일때 j의 자리는 0이므로 뽑을 필요가 없기 때문이다.
                if ((1 & bit) == 0){
                    continue;
                }
                sum = sum + arr[j];
            }
            if (sum == s) {
                result++;
            }
            sum = 0;
        }
        System.out.println(result);
 
    }
 
}


반응형
반응형

단, B에 있는 수는 재배열하면 안된다. 라는 문구가 있는데 실제 구현을 할때는 정렬로 재배열을 해줘야 한다.

예를 들어 1 2 3 4 5인 A 배열과 1 3 5 7 9 인 B 배열이 있을 때 가장 작은 수가 나올 경우는 

서로 역방향이 되어 큰값과 작은값이 곱해질 때이다. 정확히 1*9 + 2*7 + 3*5 + 4*3 + 5*1인 경우이다.

결국, A 배열과 B배열을 정렬한 다음 A와 B의 역방향으로 곱해주면 된다.


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
import java.util.Arrays;
import java.util.Scanner;
 
public class Main {
 
    public static void main(String[] args) throws Exception {
        // TODO Auto-generated method stub
 
        Scanner sc = new Scanner(System.in);
 
        int n = sc.nextInt();
 
        int[] A = new int[n];
        int[] B = new int[n];
 
        for (int i = 0; i < n; i++) {
            A[i] = sc.nextInt();
        }
        for (int i = 0; i < n; i++) {
            B[i] = sc.nextInt();
 
        }
        Arrays.sort(A);
        Arrays.sort(B);
        int sum = 0;
        for (int i = 0; i < n; i++) {
            sum += A[i] * B[n - 1 - i];
        }
        System.out.println(sum);
 
    }
}



반응형

+ Recent posts