Dreamhack/Dreamhack Wargame (Challenge)

[46] IT 비전공자 [dreamhack]rev-basic-4문제 풀기

imaginefuture-1 2024. 10. 25. 09:11

 

벌써 10월도 끝나간다..시간이 정말 빠르다는걸 느낀다. 오늘도 후회없이 살아보자!

 

rev-basic-4!

 

 

dbg 64로 correct를 찾아간다

 

 

 

 

 

 

 

 

 

여기까지 완- 그리고 어셈블리어 앞에서 포기...(눈물)

 

 

 

편-안하게 ida를 켜본다 dbg64보다 훨씬더 친절해졌다.

 

디컴파일러해보자!

 

 

아름다운 코드가 나온다.

 

 

 

주어진 C/C++ 코드의 main 함수는 사용자의 입력을 받고, 그 입력을 특정 함수로 검증하여 "Correct" 또는 "Wrong"을 출력하는 구조입니다. 각 부분을 자세히 분석하겠습니다.

코드 분석

1. 함수 서명

 
int __fastcall main(int argc, const char **argv, const char **envp)
  • int: 함수가 정수를 반환함을 나타냅니다. 일반적으로 프로그램의 종료 상태를 나타냅니다.
  • __fastcall: 호출 규약으로, 일부 인자를 레지스터를 통해 전달하여 성능을 향상시킵니다.
  • argc: 명령줄 인자의 개수입니다.
  • argv: 각 인자를 포함하는 문자열 배열입니다.
  • envp: 환경 변수를 포함하는 문자열 배열입니다.

2. 변수 선언

 
char v4[256]; // [rsp+20h] [rbp-118h] BYREF
  • char v4[256];: 크기가 256인 문자 배열을 선언하여 사용자 입력을 저장할 공간을 마련합니다. 이 배열은 스택에 할당됩니다.

3. 메모리 초기화

 
memset(v4, 0, sizeof(v4));
  • memset 함수를 사용하여 v4 배열의 모든 요소를 0으로 초기화합니다. 이는 문자열을 사용할 때의 안전성을 높이기 위한 것입니다.

4. 입력 요청

 
sub_1400011C0("Input : ", argv, envp);
  • 이 함수는 사용자에게 "Input : " 메시지를 출력하고 입력을 요청하는 것으로 추측됩니다. argv와 envp를 사용할 수 있지만, 이 함수의 구체적인 구현은 주어진 코드에서 알 수 없습니다.

5. 입력 받기

 
sub_140001220("%256s", v4);
  • 이 함수는 사용자 입력을 v4 배열에 저장합니다. "%256s" 형식 지정자는 최대 256자의 문자열을 입력받도록 설정되어 있습니다. 이는 입력을 안전하게 제한하는 것으로 보입니다.

6. 입력 검증

 
if ( (unsigned int)sub_140001000(v4) ) puts("Correct"); else puts("Wrong");
  • sub_140001000(v4) 함수는 v4에 저장된 문자열을 검증하는 함수입니다. 이 함수의 반환 값이 0이 아니면 조건이 참으로 판단됩니다.
  • 조건이 참일 경우 "Correct"를 출력하고, 거짓일 경우 "Wrong"을 출력합니다.

7. 종료

 
return 0;
  • 프로그램을 정상적으로 종료합니다.

전체적인 기능

  1. 목적: 사용자로부터 문자열 입력을 받아, 그 입력이 특정 조건을 충족하는지 검증하는 프로그램입니다.
  2. 입력 처리:
    • 사용자의 입력을 안전하게 받아오기 위해 버퍼를 초기화하고 최대 길이를 제한하고 있습니다.
  3. 검증 로직:
    • 입력된 문자열이 sub_140001000 함수에 의해 검사됩니다. 이 함수가 특정 조건을 확인하여 입력의 유효성을 판단합니다.

결론

이 main 함수는 사용자 입력을 받아서 이를 검증하는 구조를 가지고 있습니다. 함수 sub_140001000의 구현에 따라 입력된 문자열의 유효성이 결정되며, 이를 기반으로 "Correct" 또는 "Wrong" 메시지를 출력하게 됩니다. 이 코드는 입력 검증의 기본적인 패턴을 보여주며, 사용자 입력에 대한 안전성을 높이기 위한 조치를 취하고 있습니다.

 

 

성공조건을 확인하기위해 sub_140001000함수를 확인하면 이렇다.

 

 

 

 

주어진 C/C++ 코드의 sub_140001000 함수는 특정 조건을 검사하여 입력 값의 유효성을 판단하는 역할을 합니다. 아래에서 각 부분을 자세히 분석하겠습니다.

함수 서명

 
__int64 __fastcall sub_140001000(__int64 a1)
  • __int64: 함수가 64비트 정수를 반환함을 나타냅니다.
  • __fastcall: 호출 규약을 나타내며, 일부 매개변수를 레지스터를 통해 전달하여 성능을 향상시킵니다.
  • a1: 64비트 정수형 매개변수로, 검사할 데이터의 주소를 나타냅니다.

변수 선언

 
int i; // [rsp+0h] [rbp-18h]
  • i: 반복문에서 사용할 인덱스 변수입니다.

반복문

 
for ( i = 0; (unsigned __int64)i < 0x1C; ++i )
  • 이 반복문은 0부터 28(0x1C는 28의 16진수 표현)까지의 정수를 반복합니다. 총 28회 반복하게 됩니다.

조건문

 
if ( ((unsigned __int8)(16 * *(_BYTE *)(a1 + i)) | ((int)*(unsigned __int8 *)(a1 + i) >> 4)) != byte_140003000[i] ) return 0LL;
  • 이 부분은 다음과 같은 작업을 수행합니다:
    • *(unsigned __int8 *)(a1 + i): a1 주소에서 i 바이트 위치의 값을 가져옵니다. 이는 a1의 각 바이트를 검사하는 과정입니다.
    • 16 * *(_BYTE *)(a1 + i): 현재 바이트 값을 16배로 곱합니다.
    • ((int)*(unsigned __int8 *)(a1 + i) >> 4): 현재 바이트 값을 4비트 오른쪽으로 시프트하여 상위 4비트를 가져옵니다.
    • |: 두 값을 비트wise OR 연산을 수행합니다.
  • 결과적으로 이 조건문은 계산된 값이 byte_140003000[i]와 같지 않으면 0LL을 반환합니다. 즉, 조건이 만족하지 않을 경우 함수는 종료됩니다.

성공 조건

 
return 1LL;
  • 반복문이 끝까지 실행되고, 모든 비교가 성공적으로 통과하면 1LL을 반환합니다. 이는 입력값이 올바르다는 것을 나타냅니다.

전체적인 기능

이 함수의 전체적인 기능을 정리하면 다음과 같습니다:

  1. 목적: a1로 주어진 메모리 주소에 저장된 데이터를 검증하는 것입니다.
  2. 검증 방법:
    • a1에서 28바이트의 값을 읽고, 각 값에 대해 특정 계산을 수행한 후, byte_140003000 배열의 값과 비교합니다.
    • 만약 계산된 값이 byte_140003000의 해당 인덱스와 다르면 함수는 0을 반환하여 실패를 나타냅니다.
  3. 결과:
    • 모든 값이 일치하면 1을 반환하고, 하나라도 다르면 0을 반환합니다.

결론

이 함수는 특정 입력값이 기대하는 형식이나 내용을 충족하는지 검사하는 데 사용됩니다. byte_140003000 배열이 미리 정의된 기준 값을 나타내며, 입력된 데이터의 유효성을 판단하여 성공 여부를 결정하는 역할을 합니다. 이를 통해 주어진 입력 값의 무결성을 확인할 수 있습니다.

 

 


 

rev-basic-03이 xor연산이었다면 이건 두값 비교 및 or연산이다!

https://hyunhe2e.tistory.com/m/16

https://velog.io/@helenason/dreamhack-wargame-rev-basic-4

https://m.blog.naver.com/vkdrk23/222438655335

https://toma0912.tistory.com/66

 

[리버싱] rev-basic-4

# 문제https://dreamhack.io/wargame/challenges/18 rev-basic-4Reversing Basic Challenge #4 이 문제는 사용자에게 문자열 입력을 받아 정해진 방법으로 입력값을 검증하여 correct 또는 wrong을 출력하는 프로그램이 주

hyunhe2e.tistory.com

 

 

[드림핵] 워게임 rev-basic-4 풀이

안녕하세요. 해킹하는 개발자가 되고 싶은 컴공 대학생입니다. 정보 보안 분야에 관심이 많아 드림핵으로 리버스 엔지니어링 학습 중입니다. 드림핵 사이트의 워게임 rev-basic-4 문제 풀이 진행하

velog.io

 

 

[dreamhack] rev-basic-4 문제풀이

IDA로 소스코드를 확인하였다. 성공조건을 확인하기 위해 sub_140001000 함수를 확인하였다. ((16 * *(_...

blog.naver.com

 

 

자바의 연산자 및 연산자 우선순위

안녕하세요. 오늘은 Java를 공부하면서 기본적인 '연산자'에 대해서 연산자가 무엇인지, 그 종류 및 연산자 우선순위에 대해서 포스팅해보려고 합니다. 1. 연산자란? 어떠한 기능 또는 어떤 대상

toma0912.tistory.com

 

 

 

입력값을 'a'로 가정해보자

 

(16 * *(_BYTE *)(a1 + i)) | ((int)*(unsigned __int8 *)(a1 + i) >> 4)) != byte_140003000[i] )

 

(16*a1[i]) | (a1[i]>>4) !=byte_1400300[i]

 

순서는

1. 16*a1[i]

2. a1[i]>>4

3.  (16*a1[i]) | (a1[i]>>4)

 


16(10)*16진수

0xA *16(10) = 0xA0
0xB *16(10) = 0xB0
.
.
.
하나의 16진수에다가 십진수 16을 곱하면 그 결과는 16진수의 맨 오른쪽에 0을 하나 더 붙이는거랑 같다.


 

 

 

 

a1[i]>>4

 

 

0xA>>4

0000 1010>>4

0000 0101  (쉬프트 한번)

0000 0010  (쉬프트 2번)

0000 0001  (쉬프트 3번)

0000 0000  (쉬프트 4번)

 

0xA>>4는 0x0

 


 

(16*a1[i]) | (a1[i]>>4)

 

입력값이 0xA라고 모두 가정하고 모두 정리하면

0xA0 | 0x0 != byte_140003000[i]

1010 0000 | 0000 0000 != byte_140003000[i]

1010 0000 != byte_140003000[i]

 


즉, 1010 0000 과  byte_140003000[i] 를 비교하는 것이다.
그런데, 1010 0000 은 처음 입력했던 0xA 를 2진수에서 4비트끼리 앞뒤로 뒤집은 값이다.


-->
0xA   = 0000 1010 (2)
0xA0 = 1010 0000 (2)
라는 것이다.

따라서  byte_140003000[i] 에 저장되어 있는 문자들을
거꾸로 다시 앞뒤로 4비트씩 뒤집으면
Correct를 출력할 수 있는 입력값을 알 수 있다.


출처ㅣ https://aawjej.tistory.com/191

 

=> 상위 4비트와 하위 4비트를 바꾼 결과 값을 해당 연산을 통해 새로 생성하고 있다. 

.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)

 

  byte_140003000[i] 에 저장되어 있는 값들

 


24h, 27h, 13h, C6h, C6h,
13h, 16h, E6h, 47h, F5h,
26h, 96h, 47h, F5h, 46h,
27h, 13h, 26h, 26h, C6h,
56h, F5h, C3h, C3h, F5h,
E3h, E3h
로 27개 이다.

 

#include <stdio.h>

        int main() {
        int byte_140003000[27] =
        {
        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 (int i = 0; i < 27; i++) {
            printf("%c", (16 * byte_140003000[i]) & 0xF0 | (byte_140003000[i] >> 4));
        }

        return 0;
    }

 

코드 출처 https://aawjej.tistory.com/191

각 부분 설명

  1. 헤더 파일 포함:
    • 표준 입출력 함수를 사용하기 위해 stdio.h 헤더 파일을 포함합니다.
  2. c
    코드 복사
    #include <stdio.h>
  3. 메인 함수:
    • 프로그램의 진입점인 메인 함수입니다.
  4. c
    코드 복사
    int main() {
  5. 정수 배열 선언 및 초기화:
    • byte_140003000 배열을 선언하고 27개의 16진수 값을 초기화합니다. 각 값은 0x00에서 0xFF 범위의 정수입니다.
  6. c
    코드 복사
    int byte_140003000[27] = { 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 };
  7. 문자 출력 루프:
    • 배열의 각 요소에 대해 다음 작업을 수행합니다:
      • 변환:
        • (16 * byte_140003000[i]) & 0xF0: 배열의 각 요소를 16배한 값에서 상위 4비트를 추출합니다.
        • (byte_140003000[i] >> 4): 각 요소의 하위 4비트를 추출합니다.
        • 두 값을 OR 연산(|)하여 결합합니다.
      • 출력: printf("%c", ...)를 통해 변환된 값을 문자로 출력합니다.
  8. c
    코드 복사
    for (int i = 0; i < 27; i++) { printf("%c", (16 * byte_140003000[i]) & 0xF0 | (byte_140003000[i] >> 4)); }
  9. 종료:
    • 프로그램을 정상적으로 종료합니다.
  10. c
    코드 복사
    return 0;

변환 과정 예시

예를 들어, byte_140003000[0]의 값이 0x24(36)일 때, 변환 과정은 다음과 같습니다:

  1. 16 * 0x24 = 0x240 (576)
  2. 0x240 & 0xF0 = 0x240 & 0xF0 = 0x40 (64)
  3. 0x24 >> 4 = 0x2 (2)
  4. 0x40 | 0x2 = 0x42 (66), ASCII로는 B

이와 같은 방식으로 배열의 각 값이 변환되어 출력됩니다.

결론

이 코드는 주어진 정수 배열의 값을 특정 방식으로 변환한 후, 이를 ASCII 문자로 출력하는 기능을 수행합니다. 변환 방식은 각 값의 상위 비트와 하위 비트를 조합하여 새로운 문자를 생성하는 과정을 포함하고 있습니다. 이를 통해 배열의 각 요소가 어떻게 변환되는지를 확인할 수 있습니다.

 

 


또다른 분의 코드다

 

#include<stdio.h>

int main() {

    int input[28] = { 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, 0x00 };

    int flag[28] = { 0 };

    for (int i = 0; i < 28; i++) {
        flag[i] = 16 * input[i] | input[i] >> 4;
    }

    printf("flag is ");

    for (int i = 0; i < 28; i++)
        printf("%c", flag[i]);

    return 0;

}

 

출처 

https://hyunhe2e.tistory.com/m/16

 

주어진 C 코드 조각은 배열의 값을 변환하여 플래그를 생성하고, 이 플래그를 문자로 출력하는 프로그램입니다. 코드를 단계별로 분석하겠습니다.

### 각 부분 설명

1. **헤더 파일 포함**:
   ```c
   #include <stdio.h>
   ```
   - 표준 입출력 함수를 사용하기 위해 `stdio.h` 헤더 파일을 포함합니다.

2. **메인 함수**:
   ```c
   int main() {
   ```
   - 프로그램의 진입점인 메인 함수입니다.

3. **입력 배열 선언 및 초기화**:
   ```c
   int input[28] = { 
       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, 0x00 
   };
   ```
   - `input`이라는 정수 배열을 선언하고, 28개의 16진수 값으로 초기화합니다. 마지막 값 `0x00`은 문자열 종료를 나타냅니다.

4. **플래그 배열 선언**:
   ```c
   int flag[28] = { 0 };
   ```
   - `flag` 배열을 선언하고, 모든 요소를 `0`으로 초기화합니다. 이 배열은 변환된 값을 저장하는 데 사용됩니다.

5. **변환 루프**:
   ```c
   for (int i = 0; i < 28; i++) {
       flag[i] = 16 * input[i] | input[i] >> 4;
   }
   ```
   - `input` 배열의 각 요소에 대해 다음 작업을 수행합니다:
     - `16 * input[i]`: 각 요소를 16배로 증가시킵니다.
     - `input[i] >> 4`: 각 요소를 4비트 오른쪽으로 시프트하여 상위 4비트를 가져옵니다.
     - 두 값을 비트wise OR(`|`) 연산하여 결합하고, 그 결과를 `flag[i]`에 저장합니다.

6. **결과 출력**:
   ```c
   printf("flag is ");
   for (int i = 0; i < 28; i++)
       printf("%c", flag[i]);
   ```
   - "flag is "라는 문자열을 출력한 후, `flag` 배열의 각 요소를 문자로 출력합니다. 이 부분에서 변환된 값이 ASCII 코드로 해석되어 출력됩니다.

7. **종료**:
   ```c
   return 0;
   ```
   - 프로그램을 정상적으로 종료합니다.

### 변환 과정 예시

`input` 배열의 첫 번째 값 `0x24`(36)를 변환하는 과정을 살펴보면:

1. `16 * 0x24` = `0x240` (576)
2. `0x24 >> 4` = `0x2` (2)
3. `0x240 | 0x2` = `0x242` (578)

`0x242`는 ASCII 코드로는 `B`에 해당합니다.

이러한 방식으로 배열의 모든 요소가 변환되어 출력됩니다.

### 결론

이 코드는 주어진 정수 배열의 값을 변환한 후, 이를 ASCII 문자로 출력하는 기능을 수행합니다. 변환 방식은 각 값의 상위 비트와 하위 비트를 조합하여 새로운 문자를 생성하는 과정을 포함하고 있습니다. 이를 통해 배열의 각 요소가 어떻게 변환되는지를 확인할 수 있습니다.

 

 

 

flag is...