Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
botnet-hackpack — C로 기본적인 Command & Control 봇넷 구축하기 | Kitploit
도구/GitHubGitHub/treehacks/botnet-hackpack
Persistence MechanismsMalware AnalysisCommand and ControlLearning & EducationRed TeamingPayload Development
GitHubtreehacks/botnet-hackpack

botnet-hackpack

C로 기본적인 Command & Control 봇넷 구축하기

저장소 보기
403955년 전Kitploit 검토 완료

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

간단한 C&C 봇넷

이 핵팩은 봇넷의 근본적인 특성을 지닌 기본 프레임워크를 구현하는 과정을 안내합니다. C 언어를 다뤄본 적이 있다면 도움이 될 것입니다. 이 튜토리얼이 마음에 들었다면 이 저장소에 스타를 꼭 눌러 주세요!

참고: 여기서 배운 내용을 악의적인 목적으로 사용하지 마세요. 이 핵팩은 교육 목적의 봇넷 사례 연구일 뿐입니다. 이 핵팩에서 배운 개념은 매우 광범위하게 활용될 수 있습니다(기본적으로 네트워킹과 관련된 모든 것). 가장 중요한 점은, 이 핵팩은 로컬에서 테스트하고 배포하기 위한 것입니다(그러니 이 핵팩과 관련해 만든 어떤 것도 다른 해커와 공유하지 마세요). 프라이버시는 중요하니 존중해 주세요.

봇넷이란 무엇인가?

봇넷을 구축하기 전에 봇넷이 무엇인지 이해하는 것이 중요합니다. 봇넷은 원격으로 명령을 수신하고 로컬에서 실행할 수 있는 컴퓨터들의 네트워크입니다. 선택적으로 네트워크의 다른 노드로 정보를 다시 중계할 수도 있습니다. 봇넷은 분산 서비스 거부(DDoS) 공격부터 스파이웨어의 대규모 배포까지 다양한 용도로 사용되어 왔습니다. 과거에 많은 봇넷을 들어보셨을 것입니다. 가장 대표적인 것은 각각 3,800대와 360만 대의 IoT 기기를 제어했던 Mirai와 Gameover Zeus입니다. 봇넷이 특정 작업을 구현하는 방식은 매우 다양합니다. 하지만 봇넷을 성공적으로 구축하려면 우리가 구성할 네트워크에서 다음 기능을 보장해야 합니다.

우리의 봇넷은 다음을 충족해야 합니다:

  1. 네트워크의 다른 모든 노드를 제어하는 마스터 노드를 포함할 것
  2. 호스트 컴퓨터에 위장된 멀웨어/슬레이브 노드를 배포할 것
  3. 마스터 노드에서 슬레이브 노드로 명령을 전송하고, 실행한 후 출력을 마스터에게 돌려보낼 것

이 구조는 소위 C&C(Command & Control) 봇넷의 특징입니다. 이러한 봇넷은 마스터 서버 하나와 많은 슬레이브 서버를 가집니다. 하지만 이런 스타일의 봇넷은 구식이며 마스터 도메인에 대한 접근을 차단함으로써 쉽게 무력화될 수 있습니다. 더 최신이고 정교한 봇넷은 P2P(피어투피어) 아키텍처를 따르며, 관리 권한이 네트워크의 모든 노드 또는 일부 노드에 분산됩니다. 이러한 봇넷은 중앙 제어 지점이 없고 수백만 개의 노드로 성장할 수 있기 때문에 보안 전문가들에게 골칫거리입니다. 그러한 봇넷을 무력화하는 것 자체도 흥미로운 읽을거리입니다. 하지만 이 핵팩의 목적을 위해 단순하게 유지하겠습니다. C&C 봇넷용 간단한 슬레이브 노드를 구현할 것입니다.

alt tag

구현

마스터

이 핵팩은 주로 클라이언트 멀웨어 구현을 다룹니다. 마스터 서버로는 오픈소스 TCP 서버인 Netcat을 사용할 수 있습니다. Netcat은 봇넷과 아무 관련이 없습니다. 단지 클라이언트와 텍스트 패킷을 주고받기 위해 재사용할 수 있는 편리하고 검증된 도구일 뿐입니다(마스터가 실제로 하는 일은 이것이 전부입니다). 저는 Netcat 서버를 약간 수정하여 "master"라는 바이너리로 컴파일했습니다. 더 할 일은 없습니다! 마스터는 사용할 준비가 되었습니다.

슬레이브

이제 더 흥미로운 부분인 원격 명령 수신 및 실행으로 넘어갑시다(멀웨어 위장에 대해서는 나중에 다루겠습니다). 여기서의 목표는 슬레이브 노드를 가능한 한 단순하게 만들고 위에 설명된 요구 사항을 따르는 것입니다. 많은 상수들이 lib/macros.h에 정의되어 있으니 자유롭게 사용하세요. 구현된 모든 함수 시그니처는 lib/connect.h 또는 lib/utils.h에서 찾을 수 있습니다.

1. 초기화

bot.c 파일을 엽니다. 서버에서 새 노드를 시작할 때, 마스터가 어떤 클라이언트에 명령을 배포할지 알 수 있도록 노드에 이름을 붙여야 합니다. 사용할 수 있는 명명 규칙은 많습니다. IP 주소는 각 클라이언트의 고유 식별자이므로 아마 최선일 것입니다. 하지만 일반인이 읽기 쉽게 하기 위해 컴퓨터의 사용자 이름을 사용합시다. C 함수 getenv()에 인자 "USER"를 전달하면 컴퓨터가 USER 환경 변수에 저장해 둔 값을 반환합니다. 사용자의 사용자 이름이 저장되는 장소 중 하나이므로 그것을 사용합시다. 또한 이제 슬레이브가 실행 중이므로 마스터를 찾아봅시다. 그러려면 마스터의 IP 주소를 알아야 합니다. 모든 네트워크 장치에는 IP 주소가 있습니다. IP 주소는 다른 노드를 식별하고 위치 주소를 지정하는 역할을 합니다. 게다가 마스터는 서로 다른 포트에서 여러 서버를 실행할 수 있습니다. 따라서 마스터에 연결하는 것뿐만 아니라 올바른 포트도 지정해야 합니다. 이 포트는 마스터가 선택하지만 변경할 수 있습니다. 이 핵팩에서는 로컬에서 테스트하려고 합니다. 따라서 컴퓨터를 네트워크로 사용할 것입니다. 모든 컴퓨터의 로컬 IP 주소("localhost"도 결국 이 주소로 해석됩니다)는 "127.0.0.1"입니다. 마스터에서 포트 9999에서 실행되도록 지정했습니다. 이 세 가지(마스터 IP 주소, 마스터 포트, 슬레이브 이름)를 사용하여 서버와 클라이언트 사이의 통신 파이프라인인 소켓을 시작할 수 있습니다. 이 세 인자를 init_socket() 함수에 전달하여 소켓을 생성하세요. init_function()은 C 내장 명령이 아닙니다. 우리가 직접 구현해야 합니다. 그런 다음 수신 메시지를 담을 스택 공간을 할당해야 합니다. 여유 있게 약 10KB의 스택 공간을 사용합시다. 이 스택 포인터를 msg라고 부르세요. 마지막으로 모든 것이 잘 진행되고 있음을 알리는 printf 문이 있습니다.

root@kitploit:~
char* name = //Get the client's username and store it in name
int channel = //initiate a channel given SERVER, PORT, and name;
//Allocate stack space of size CMD_LENGTH to hold data of type char. Call the stack pointer msg
printf("%s joining the botnet\n", name);

이제 lib/connect.c로 전환합시다. init_channel()을 구현합시다. 먼저 길이가 CMD_LENGTH인 스택 char 버퍼 msg와 마스터와의 연결 정보를 담는 특별한 C 네트워킹 구조체 server를 정의했습니다. 먼저 전달받은 IP 주소를 사람이 읽을 수 있는 형식(숫자와 점)에서 네트워크 바이트 순서의 이진 형식으로 변환하세요. 이 작업은 소켓 라이브러리의 특별한 C 함수 inet_addr()을 사용하여 수행합니다. 이 함수는 IP 주소를 받아 네트워크에서 사용 가능한 이진 형식으로 바꿔 줍니다. C에서는 sockaddr_in이라는 구조체의 필드를 채워 네트워크를 쉽게 지정할 수 있습니다. 이 구조체의 인스턴스는 server라고 부릅니다. 이 구조체의 세 가지 필드를 채워야 합니다: server.sin_addr.s_addr(마스터 IP 주소), server.sin_family(통신 도메인을 지정하는 1바이트 값), server.sin_port(마스터에서 연결할 포트). sin_family에는 소켓 라이브러리에서 제공하는 C 매크로를 사용할 수 있습니다. 일반적으로 이 경우처럼 이 필드를 AF_INET으로 설정합니다. 이는 연결이 IP 주소를 통해 네트워크 노드를 식별한다는 뜻이며, 우리가 원하는 방식입니다. 그러나 PF_INET을 사용할 수도 있습니다. AF_INET과 비슷하지만 프로토콜 내의 무엇이든 사용하여 특정 노드를 식별할 수 있도록 지정합니다. 두 매크로가 모두 존재하는 데는 역사적 이유가 많다고 알려져 있지만, 저는 그것에 대해 잘 알지도 못하고 크게 관심도 없습니다. 그냥 AF_INET을 사용하세요. 마지막으로 서버 포트를 설정할 때 port를 (호스트-투-네트워크 숏)라는 특별한 함수에 통과시켜야 합니다. 이 함수는 데이터를 호스트 바이트 순서에서 네트워크 바이트 순서로 변환합니다. 이 바이트 순서 문제는 엔디언(Endianness)이라고 하는 것과 관련이 있습니다. 자세한 내용은 에서 읽을 수 있습니다.

마지막으로 마스터와 슬레이브 사이의 실제 연결을 정의해야 합니다! 이를 위해 데이터를 보낼 수 있는 네트워크 소켓을 정의하세요. 마스터에 '전기 콘센트'가 많이 있다고 생각해 보세요. 이제 슬레이브 측에서 마스터의 '벽면 콘센트'에 맞는 '플러그'를 만들어야 합니다. 소켓 라이브러리의 socket() 함수를 사용하면 됩니다. 정말 편리하죠! socket()은 통신 도메인, 소켓 유형, 프로토콜의 세 가지 인자를 받습니다. 통신 도메인은 이미 짐작하셨겠지만 AF_INET입니다. 소켓 유형은 양방향으로 데이터를 스트리밍하는 소켓을 원하므로 주어진 매크로 SOCK_STREAM을 사용하세요. 소켓 프로토콜에 대해서는 걱정하지 맙시다. 상당히 기본적인 네트워크이므로 기본 프로토콜을 의미하는 값 0을 사용합시다. 이 함수는 소켓을 나타내는 int를 반환합니다. 이 값을 channel에 저장하세요. 다음으로 소켓을 시작(슬레이브를 마스터의 벽면 콘센트에 꽂기)하려고 합니다. C 함수 connect()를 호출하세요. 이 함수는 channel, sockaddr 구조체, 구조체의 바이트 크기의 세 인자를 받습니다. connect()가 양의 정수를 반환하면 마스터와의 연결이 성공한 것입니다! 새로 만든 연결을 테스트하기 위해 마스터에게 인사말을 보내 봅시다! 메시지 버퍼를 채우고 respond()(아직 구현되지 않음)를 사용하여 msg를 channel을 통해 마스터에게 보내세요. 마지막으로 init_channel() 함수가 이 성공적인 연결을 반환하도록 해야 합니다.

root@kitploit:~
int init_channel (char *ip, int port, char *name) {
	char msg[CMD_LENGTH];
	struct sockaddr_in server;

	server.sin_addr.s_addr = //convert the ip to network byte order
	server.sin_family = //set the server's communications domain
  server.sin_port = //convert port to network byte order
  
  int channel = //define a SOCK_STREAM socket
  
  if(channel < 0) {
    perror ("socket:");
    exit(1);
  }
  
  int connection_status = //use the defined channel to connect the slave to the master server
  
  if (connection_status < 0) {
    perror ("connect:");
    exit(1);
  }

  //send a greeting message back to master by loading a string into msg (hint: snprintf will come in handy)
  respond (channel, msg);
  return channel;
}

2. 메시지 수신 대기

슬레이브가 마스터에 연결되면 명령을 받기 위해 계속 메시지를 수신하고 즉시 실행해야 합니다. 따라서 무한 while 루프를 사용하여 이러한 메시지를 수신하고 파싱합시다. bot.c에서 printf 문 아래에 두 함수 recieve()와 parse()를 순서대로 호출하는 무한 while 루프를 추가하세요. 두 함수 모두 인자로 channel과 msg 스택 버퍼를 받습니다. 함수 시그니처는 lib/utils.h에서 찾을 수 있습니다. 대략 다음과 같은 형태입니다:

root@kitploit:~
Infinite Loop {
  recieve(...);
  parse(...);
}

utils.c로 가서 recieve()와 respond()를 구현하세요. recieve()는 채널에서 메시지를 가져오고, respond()는 채널을 통해 메시지를 다시 보냅니다. respond()의 매개변수는 소켓 주소 s와 스택 버퍼 msg_buf입니다. C 함수 write()를 사용하여 스택 버퍼에 들어 있는 내용을 채널에 쓰고 그 상태를 반환하려고 합니다. write()는 소켓 주소, 메시지 버퍼, 메시지 길이의 세 인자가 필요합니다.

root@kitploit:~
int respond(int s, char *msg_buf) {
    //write the contents of msg_buf into socket s and return status
}

recieve()도 간단한 헬퍼 함수입니다. msg 버퍼를 초기화하세요(힌트: memset() 사용). 이제 소켓 라이브러리 함수 read()를 호출하여 msg를 읽으세요. read()는 소켓 주소, 메시지 버퍼, 기대되는 최대 메시지 길이의 세 인자를 받습니다.

root@kitploit:~
int recieve(int s, char *msg) {
    //reset the msg buffer
    int read_status = //read contents of socket s into msg
    if (read_status) {
      perror("log:");
      exit(1);
    }
    return 0;
}

3. 명령 실행

거의 다 됐습니다! 지금 우리 봇넷은 꽤 지루합니다. 소켓을 통해 메시지를 수신하고 전송만 할 수 있습니다. 이제 수신한 내용을 터미널에서 실제로 실행하게 만들어 봅시다. 먼저 parse() 함수를 구현합니다. 이 함수는 이름이 의미하는 그대로 명령을 파싱합니다. 메시지가 잘못된 형식인지 확인하는 간단한 오류 검사를 할 수 있습니다. 또한 수신했지만 자신을 대상으로 하지 않은 메시지는 조용히 무시하려고 합니다. 마스터가 보내는 메시지 형식은 (봇넷 이름):(실행할 명령)입니다. 전자는 여러분을 위해 이미 구현해 두었습니다. 두 검사를 통과하면 명령을 execute() 함수에 전달합시다.

root@kitploit:~
int parse (int s, char *msg, char* name) {
  char *target = msg;
  
  //check whether the msg was targetted for this client. If no, then silently drop the packet by returning 0
  
  char *cmd = strchr(msg, ':');
  if (cmd == NULL) {
    printf("Incorrect formatting. Reference: TARGET: command");
    return -1;
  }
 
  //adjust the cmd pointer to the start of the actual command
  //adjust the terminated character to the end of the command
  //print a local statement detailing what command was recieved
  
  execute (s, cmd);
  return 0;
}

이제 멋진 부분입니다. execute()는 수신한 명령을 터미널로 파이프하고 모든 출력을 소켓을 통해 마스터에게 써야 합니다. 각 입력 줄을 저장할 스택 버퍼를 만드세요. 그런 다음 C 함수 popen()을 사용하여 입력을 실행하고 출력을 파일 f에 저장하세요(이 시점에서 접근 방식은 다양합니다. 마스터 입력으로 정말 멋진 작업을 수행하도록 봇넷을 커스터마이즈하고, 봇넷의 다른 노드와 자율적으로 협력하거나 업데이트를 수행할 수 있습니다. 원하는 만큼 창의력을 발휘하세요. 우리는 지금 당장은 기본 목표를 고수할 것입니다). f를 줄 단위로 파싱하고 모든 내용을 소켓으로 덤프하세요. f를 닫으면 끝입니다!

root@kitploit:~
int execute (int s, char *cmd) {
  FILE *f = //use popen to run the command locally
  if (!f) return -1;
  while (!feof (f)) {
    //parse through f line by line and send any output back to master
  }
  fclose(f);
  return 0;
}

다음 터미널 명령으로 새 봇넷을 컴파일하세요:

root@kitploit:~
gcc -lcurl lib/connect.c lib/utils.c bot.c -o bin/slave

하나의 터미널 창에서 bin/master를 실행하고 다른 창들에서 bin/slave를 실행하세요. 명령은 (슬레이브 사용자 이름):(원격 터미널 명령) 형식으로 입력하세요. 축하합니다! 방금 봇넷을 구축했습니다!

4. 멀웨어 위장하기

멀웨어를 위장하고 배포하는 데 사용할 수 있는 정말 멋진 방법들이 많습니다. 사실 그 자체로 하나의 분야입니다. 할 수 있는 예 중 하나는 멀웨어를 이미지로 가장하는 것입니다. 판다 이미지를 사용해 봅시다. 저는 utils.c에 판다 이미지를 curl로 가져와 Preview로 보여 주는 간단한 함수를 추가했습니다. 이렇게 하면 사용자가 판다 이미지를 여는 것처럼 보이지만, 실제로는 사용자가 멀웨어를 실행하는 것입니다. 이를 추가하려면 다음 코드 줄을 bot.c에 포함하세요:

root@kitploit:~
char* open_cmd = alias_img();
system(open_cmd);
free(open_cmd);

다음으로 아무 이미지나 마우스 오른쪽 버튼으로 클릭하고 정보 가져오기를 선택하세요. bin/slave에도 동일하게 하세요. 이미지 썸네일을 bin/slave 실행 파일 썸네일 위로 끌어다 놓으세요. 그러면 바탕화면에서의 모양이 바뀔 것입니다. 하지만 아직 .png 파일 확장자가 빠져 있습니다. 실행 파일 이름을 다음으로 바꾸세요:

root@kitploit:~
panda⒈png

이제 이것은 png 파일처럼 보입니다. 하지만 우리는 "." 대신 유니코드 문자 "1."을 사용하여 여전히 Unix 실행 파일이라는 사실을 숨깁니다. LEFT-TO-RIGHT OVERRIDE 문자처럼 실행 파일 이름을 위장하는 더 그럴듯한 Unix 트릭도 많이 사용할 수 있습니다. 더 극단적인 경우에는 이미지와 파일 매크로 안에 코드를 삽입하여 호스트가 열릴 때 동시에 실행되게 할 수 있습니다(일종의 트로이 목마처럼....). 그러나 TreeHacks에는 사이버 범죄자가 없으므로 그런 기술에 대해 크게 신경 쓸 필요는 없습니다 ;).

5. 확장

이제 완전히 동작하는 봇넷이 생겼으니, 스스로 도전해 볼 수 있는 확장이 많이 있습니다. 우리의 봇넷은 여전히 별로 흥미롭지 않습니다. 사용자가 매번 클릭하지 않으면 할 수 있는 일이 많지 않습니다. 몇 가지 제안은 다음과 같습니다:

1. 지속성(Persistence) 달성

봇넷은 컴퓨터가 종료된 후에도 어떻게든 컴퓨터에 남아 있을 수 있다면 공격자에게 진정으로 신뢰할 수 있는 악성 활동의 원천이 될 수 있습니다. 시작할 때마다 슬레이브를 다시 실행할 방법을 시험해 보세요. 이렇게 하면 사용자가 멀웨어를 한 번 클릭하면 스스로 청소하기 전까지 컴퓨터가 감염됩니다. 이를 달성하기 위한 한 가지 제안은 실행 프로세스를 데몬으로 만드는 것입니다. 그런 다음 시작 시 실행되어야 하는 데몬 목록에 실행 파일을 추가하는 구성 파일을 생성하세요(클라우드 스토리지 애플리케이션, 팀 메시징 플랫폼 등은 이미 이렇게 합니다). 자세한 내용은 여기에서 확인하세요.

2. 피어 투 피어 네트워크 구현

피어 투 피어 네트워크를 구현하는 것은 네트워크 설계를 재배치하는 것에 불과합니다. 하지만 P2P 네트워크의 핵심은 관리자/공격자가 네트워크의 어떤 노드를 통해서든 마스터 제어권을 얻을 수 있다는 것입니다. 따라서 공격자는 어떤 노드에 대해서도 마스터 제어를 허용하는 일종의 마스터 키와 암호화된 로그온을 가져야 합니다. 피어 투 피어 네트워크가 어떻게 작동하는지 자세히 알아보려면 여기를 읽어 보세요.

3. 여러 단계의 미스디렉션 추가

구현한 마스터-슬레이브 구조는 그리 안전하지 않습니다. 슬레이브는 마스터 노드를 죽임으로써 쉽게 해방될 수 있습니다. 이상적으로는 P2P 설계로 전환하는 것이 좋습니다. 그러나 마스터의 명령을 봇넷에 배포하기 전에 공격자가 제어하는 일련의 봇들을 무작위로 거치게 하여 마스터의 보안을 약간 높일 수도 있습니다. 그러면 전문가들이 명령의 중심을 찾고 공격자 노드와 클라이언트 노드 사이의 봇넷 호출을 추적하기가 더 어려워집니다.

4. 적절한 네트워크 프로토콜 탐구

아마 더 중요한 것은 네트워킹을 더 많이 다뤄 보고 싶을 것입니다. 우리의 네트워크는 가장 단순한 형태입니다. 여러모로 매우 취약하고 확실히 엄밀하지 못합니다. 따라서 IRC(Internet Relay Chat)와 같은 확립된 네트워크 프로토콜을 살펴보며 더 제대로 된 네트워크를 구축하고 싶을 수도 있습니다. 시간이 걸리지만 매우 교육적이고 가치 있는 투자입니다. 자세한 내용은 여기에서 읽어 보세요: https://oramind.com/tutorial-how-to-make-an-irc-server-connection/.

5. 나만의 마스터 구현 시도

이 핵팩에서는 자유롭게 사용할 수 있는 오픈소스 프로젝트를 마스터 서버 대신 사용했습니다. 하지만 여기에는 많은 단점이 있습니다. 첫째, 마스터 서버를 커스터마이즈하여 네트워크를 통해 자동 명령을 보낼 수 없습니다. 명령줄 입력만 사용할 수 있습니다. 둘째, 봇넷의 모든 슬레이브가 모든 명령을 수신한다는 것을 눈치챘을 것입니다. 실행 조건은 대상 이름이 슬레이브 이름과 일치하는지 확인하는 것입니다. 일치하지 않으면 명령은 조용히 버려집니다. 이를 브로드캐스트 네트워크라고 합니다. 더 최적화된 방법은 멀티캐스트 네트워크일 수 있습니다. 브로드캐스트 네트워크에서는 노드가 연결된 모든 노드에 패킷을 중계합니다. 멀티캐스트 시스템에서는 패킷을 수신할 특정 노드 부분 집합을 지정할 수 있습니다. 또한 멀티캐스트 네트워크를 사용하면 명령 할당 작업이 클라이언트에서 그 역할이 있어야 할 마스터 서버로 이동합니다. 봇넷을 브로드캐스트에서 멀티캐스트로 전환하려면 나만의 마스터를 구현하세요.

네트워크 프로그래밍에 대한 전반적인 가이드는 다음을 참조하세요: http://beej.us/guide/bgnet/output/html/multipage/index.html.

재미있게 보셨기를 바랍니다!

라이선스

MIT

HackPacks 소개 🌲

HackPacks는 매년 2월 스탠포드에서 열리는 해커톤에서 해커들이 멋진 프로젝트를 만들 수 있도록 TreeHacks 팀이 제작했습니다. 우리는 어떤 실력 수준이든 누구나 멋진 것을 만드는 법을 배울 수 있다고 믿으며, 이것이 해커 문화를 촉진하는 데 도움이 되는 방법 중 하나입니다. 우리는 모든 사람이 배우고 사용할 수 있도록 핵팩(과 내부 기술)을 오픈소스로 공개합니다! 여러분의 해커톤, 워크숍, 그리고 빌딩을 장려하는 모든 곳에서 자유롭게 사용하세요 :)

TreeHacks 참가에 관심이 있다면 신청 기간 동안 웹사이트에서 지원할 수 있습니다.

GitHub에서 저희가 하는 모든 오픈소스 작업을 보려면 팔로우해 주세요(이슈, 기여, 모든 종류의 피드백을 환영합니다!). Facebook, Twitter, Instagram에서도 TreeHacks의 일반적인 소식을 만나보세요.

도구 다운로드
htons()
여기