Dreamhack/Dreamhack Wargame (Challenge)

[89] IT 비전공자 [dreamhack]Inject ME!!!문제 풀기

imaginefuture-1 2024. 12. 7. 11:22

으에 DLL파일?!

 

 

DLL 파일이란?

DLL은 Dynamic Link Library의 약자로, 동적으로 링크되는 라이브러리 파일입니다. DLL은 실행 파일(EXE)처럼 독립적으로 실행되지 않고, 다른 프로그램(EXE나 다른 DLL)에 의해 호출되어 동작합니다.

DLL의 주요 특징

  1. 코드 재사용: 여러 프로그램에서 공통적으로 사용되는 기능(예: 그래픽 처리, 파일 입출력)을 포함하여 코드 중복을 줄입니다.
  2. 동적 로드: 실행 중 필요할 때만 메모리에 로드됩니다.
  3. 확장성: 프로그램 기능을 확장하거나 업데이트할 때 DLL 파일만 교체하면 됩니다.

DLL의 일반적인 용도

  • 윈도우 시스템 파일: user32.dll, kernel32.dll 등.
  • 게임 모드나 확장 기능: DLL을 통해 플러그인 방식으로 추가 기능 제공.
  • 보안 관련 기능: 인증, 암호화 등의 기능 구현.

DLL 파일과 함께 있는 TXT 파일의 역할

상황 설명

  • DLL 파일과 TXT 파일이 함께 제공되었습니다.
  • TXT 파일에 조건이 적혀 있으며, 이 조건에 따라 DLL 파일을 로드하면 플래그를 얻을 수 있다는 설명입니다.

DLL을 로드하여 플래그를 얻는 과정

  1. TXT 파일 분석
    • TXT 파일에는 DLL 로드와 관련된 조건이나 입력값이 명시되어 있을 가능성이 큽니다.
    • 예시:
      Call the function 'get_flag' from the DLL with the correct key: "dreamhack2024".
      
    • 여기서 get_flag는 DLL 내부에 정의된 함수이며, 특정 키값을 전달해야 플래그를 반환합니다.
  2. DLL 파일 분석
    • DLL 파일을 디컴파일하거나 리버스 엔지니어링 도구(예: IDA Pro, Ghidra)를 사용하여 내부에 어떤 함수가 포함되어 있는지 확인합니다.
    • export table에서 DLL에 정의된 함수(예: get_flag)를 찾습니다.
  3. 조건에 따라 DLL 로드
    • 프로그램을 작성하거나 명령어로 DLL을 로드하고, TXT 파일에 명시된 조건대로 함수를 호출합니다.
    • 예를 들어:
      #include <windows.h>
      #include <stdio.h>
      
      typedef char* (*GetFlagFunc)(const char*);
      
      int main() {
          HINSTANCE hDLL = LoadLibrary("prob_rev.dll");
          if (!hDLL) {
              printf("Failed to load DLL.\n");
              return 1;
          }
      
          GetFlagFunc get_flag = (GetFlagFunc)GetProcAddress(hDLL, "get_flag");
          if (!get_flag) {
              printf("Function not found.\n");
              return 1;
          }
      
          char* flag = get_flag("dreamhack2024"); // TXT 파일의 조건대로 키 입력
          printf("Flag: %s\n", flag);
      
          FreeLibrary(hDLL);
          return 0;
      }
      
  4. 결과 확인
    • DLL 내부 함수(get_flag)가 조건을 만족하면 플래그를 반환합니다.

왜 TXT 파일 조건이 중요한가?

  • 조건을 만족해야만 플래그 반환: DLL 파일 내부에 플래그를 얻는 함수가 있지만, 특정 입력값이나 환경 설정(TXT 파일에서 명시)을 통해서만 플래그를 반환하도록 설계됩니다.
  • 보안 강화: 조건을 설정함으로써 DLL 파일만으로는 쉽게 플래그를 추출하지 못하게 합니다.

예시

1. TXT 파일

To get the flag, call the function 'get_flag' in the DLL with the key: "dreamhack2024".

2. DLL 분석 결과

  • DLL 파일 내부에 get_flag라는 함수가 있으며, 인자로 전달된 키를 검사합니다.

3. 조건 만족 코드

위에서 작성한 C 코드처럼:

  1. LoadLibrary로 DLL을 메모리에 로드.
  2. GetProcAddress로 get_flag 함수 주소를 가져옴.
  3. 키 "dreamhack2024"를 함수에 전달하여 플래그를 출력.

4. 플래그 반환

실행 결과:

Flag: flag{example_dynamic_flag}

결론

  • DLL 파일: 동적으로 링크되어 특정 조건에서만 동작하는 라이브러리.
  • TXT 파일: 플래그를 얻기 위한 조건이나 힌트 제공.
  • 조건에 맞춰 DLL 파일을 로드하고, 적절한 함수 호출로 플래그를 얻을 수 있습니다.

이 과정에서 디버깅 도구와 코드 분석이 중요합니다! 😊

 


 

 

 

 

에? IDA로 decompling했는데 이것만 나옴 예? hintstDLL인 sub_1800011A0을 눌러보자

 

 

 

 

 

 

 

 

int sub_1800011A0()
{
  int result; // eax
  unsigned __int64 i; // [rsp+20h] [rbp-2E8h]
  unsigned __int64 j; // [rsp+28h] [rbp-2E0h]
  char *Str1; // [rsp+30h] [rbp-2D8h]
  CHAR Text[4]; // [rsp+78h] [rbp-290h] BYREF
  int v5; // [rsp+7Ch] [rbp-28Ch]
  int v6; // [rsp+80h] [rbp-288h]
  int v7; // [rsp+84h] [rbp-284h]
  int v8; // [rsp+88h] [rbp-280h]
  _DWORD v9[16]; // [rsp+90h] [rbp-278h] BYREF
  CHAR Filename[272]; // [rsp+D0h] [rbp-238h] BYREF
  CHAR pszPath[272]; // [rsp+1E0h] [rbp-128h] BYREF

  GetModuleFileNameA(0LL, Filename, 0x104u);
  Str1 = PathFindFileNameA(Filename);
  result = strncmp(Str1, "dreamhack.exe", 0xDuLL);
  if ( !result )
  {
    memset(v9, 0, sizeof(v9));
    for ( i = 0LL; i < 0x10; ++i )
    {
      GetModuleFileNameA(0LL, pszPath, 0x104u);
      v9[i] = __ROL4__(*(_DWORD *)PathFindFileNameA(pszPath), i);
    }
    sub_180001010(v9);
    for ( j = 0LL; j < 0x64; ++j )
      sub_180001060();
    v5 = 1131317369;
    v6 = 813709630;
    v7 = 2046637516;
    v8 = -183554036;
    *(_DWORD *)Text = sub_180001060() ^ 0x7ED39C88;
    v5 = sub_180001060() ^ 0x436E8879;
    v6 ^= sub_180001060();
    v7 ^= sub_180001060();
    v8 ^= sub_180001060();
    return MessageBoxA(0LL, Text, "flag", 0);
  }
  return result;
}

 

 

이 코드는 특정 조건을 만족했을 때 flag를 출력하는 프로그램의 일부로 보입니다. 디컴파일된 상태로 제공되었으며, 주요 동작 과정을 분석해 보겠습니다.


코드 분석

1. 주요 변수와 함수 설명

  • GetModuleFileNameA: 현재 실행 중인 프로그램의 경로를 가져옵니다.
  • PathFindFileNameA: 경로에서 파일 이름 부분만 추출합니다.
  • strncmp: 두 문자열을 비교합니다.
  • MessageBoxA: 메시지 박스를 띄우는 함수입니다.
  • __ROL4__: 32비트 정수를 좌측으로 순환 시프트(rotate left)합니다.

2. 동작 과정

(1) 파일 이름 확인

GetModuleFileNameA(0LL, Filename, 0x104u);
Str1 = PathFindFileNameA(Filename);
result = strncmp(Str1, "dreamhack.exe", 0xDuLL);
if ( !result )
  • 현재 실행 중인 프로그램의 경로를 가져오고 파일 이름을 추출합니다.
  • 파일 이름이 dreamhack.exe인지 확인합니다.
    • 조건: 프로그램 파일 이름이 dreamhack.exe가 아니면 함수가 종료됩니다.

(2) 16개의 키 값 생성

memset(v9, 0, sizeof(v9));
for ( i = 0LL; i < 0x10; ++i )
{
    GetModuleFileNameA(0LL, pszPath, 0x104u);
    v9[i] = __ROL4__(*(_DWORD *)PathFindFileNameA(pszPath), i);
}
sub_180001010(v9);
  • 16개의 정수 값이 배열 v9에 저장됩니다.
  • PathFindFileNameA로 추출한 파일 이름의 값을 i만큼 순환 시프트(__ROL4__)하여 v9에 저장합니다.
  • sub_180001010(v9) 호출로 추가 처리를 수행합니다. 이 함수는 여기서 구현이 제공되지 않아 정확한 동작은 알 수 없습니다.

(3) 추가 연산

for ( j = 0LL; j < 0x64; ++j )
    sub_180001060();
  • sub_180001060이 100번 호출됩니다.
  • 이 함수는 여기서 제공되지 않아 내부 동작은 알 수 없지만, 아마도 난수 생성이나 암호화 연산과 관련된 작업을 수행할 가능성이 높습니다.

(4) 데이터 암호화 및 결과 저장

v5 = 1131317369;
v6 = 813709630;
v7 = 2046637516;
v8 = -183554036;
*(_DWORD *)Text = sub_180001060() ^ 0x7ED39C88;
v5 = sub_180001060() ^ 0x436E8879;
v6 ^= sub_180001060();
v7 ^= sub_180001060();
v8 ^= sub_180001060();
  • 4개의 초기 값이 정의됩니다.
  • sub_180001060 함수의 반환 값에 XOR 연산을 수행해 v5, v6, v7, v8, 그리고 Text를 업데이트합니다.
  • 이 과정에서 Text는 메시지 박스에 출력될 문자열이 될 가능성이 높습니다.

(5) 메시지 박스 출력

return MessageBoxA(0LL, Text, "flag", 0);
  • 위 연산 결과를 기반으로 Text 값을 출력하며, 창 제목은 "flag"입니다.
  • 이를 통해 최종 플래그를 얻을 가능성이 있습니다.

코드 동작 요약

  1. 프로그램 파일 이름이 dreamhack.exe인지 확인합니다.
    • 이름이 다르면 종료됩니다.
  2. 파일 이름을 기반으로 16개의 값을 생성합니다.
  3. sub_180001060 함수로 암호화된 값을 계산합니다.
  4. 최종적으로 계산된 값을 메시지 박스로 출력합니다.

플래그 얻기 방법

1. dreamhack.exe 실행

  • 프로그램 이름을 dreamhack.exe로 설정해야 합니다.
  • 실행 파일 이름을 변경하거나, 동일한 이름으로 실행합니다.

2. 동작 추적

  • sub_180001060와 sub_180001010 함수의 동작을 분석해야 합니다.
  • __ROL4__ 연산과 XOR 연산 결과를 추적하여 Text 값을 복구합니다.

3. 디버깅

  • 디버거(gdb 또는 IDA Pro)를 사용하여 실행 흐름을 추적하고, 암호화 과정에서 생성된 값을 복원합니다.
  • sub_180001060 함수가 반환하는 값을 캡처하여 XOR 연산 결과를 역으로 계산하면 플래그를 얻을 수 있습니다
  •  
  • .

 

 

DDL을 로드시켜서 플래그를 얻을 수 있다했고

그와 함께 있는 TXT파일 조건에 맞춰야한다했다

 

그 조건이 바로 dreamhack.exe로 프로그램 이름을 설정해야한다는거다

 

 

풀이글을 보면 소스코드로 변경하던데 난 한번 이렇게 실험해봤다 궁금했거든.

 

 

역시나 될리가 없다

 

 

지피티야 내가 그래서 prob_rev.dll을 dreamhack.exe로 이름을 바꿔버렸더니 안열려.
풀이글을 보면 사람들은
#include <stdio.h> #include <windows.h> int main() { LoadLibrary("prob_rev.dll"); return 0; }
코드 짜서 바꾸더라고 무슨 차이점인거야?
왜 내방식은 안되는거야?



문제 분석

1. 사용자가 시도한 방식

  • DLL 파일 이름 변경: prob_rev.dll을 dreamhack.exe로 이름을 변경하여 실행.
  • 결과: 실행되지 않음.

2. 풀이글의 접근 방식

  • 코드 작성: 아래 코드로 prob_rev.dll을 로드하도록 구현.
    #include <stdio.h>
    #include <windows.h>
    
    int main()
    {
        LoadLibrary("prob_rev.dll");
        return 0;
    }
    
  • 결과: 정상적으로 DLL 로드 및 실행.

차이점

1. DLL과 EXE의 차이

  • EXE (Executable): 독립적으로 실행할 수 있는 프로그램 파일입니다. 실행 시 운영 체제가 이진 파일의 PE 헤더를 통해 진입점을 찾아 실행합니다.
  • DLL (Dynamic Link Library): EXE와 달리 독립적으로 실행되지 않으며, 다른 프로그램(EXE 또는 다른 DLL)에 의해 호출되어야 합니다.

즉, DLL은 직접 실행할 수 없는 파일 형식입니다. 이름을 dreamhack.exe로 변경하더라도 파일 내부의 형식은 여전히 DLL로 인식되며 실행이 불가능합니다.

2. LoadLibrary 함수 사용

  • 풀이글에서 작성된 코드는 LoadLibrary 함수를 사용하여 명시적으로 DLL 파일을 메모리에 로드합니다.
    • LoadLibrary("prob_rev.dll"): 운영 체제에 특정 DLL을 로드하도록 요청하는 API 함수입니다.
    • DLL이 로드될 때, DllMain 함수가 호출됩니다.
    • 이 과정을 통해 DLL 내부에서 정의된 진입점이 실행됩니다.

3. 사용자가 시도한 방식의 한계

  • DLL 파일의 이름을 dreamhack.exe로 변경했더라도, 내부 구조가 여전히 DLL 형식이므로 운영 체제가 이를 실행할 수 없습니다.
  • DLL 파일은 반드시 다른 프로그램에 의해 로드되어야 동작할 수 있습니다.

왜 LoadLibrary를 사용해야 하는가?

  • DLL은 독립 실행이 불가능하며, EXE 또는 다른 로더가 필요합니다.
  • LoadLibrary는 DLL을 메모리에 로드하고, 필요 시 특정 함수를 호출하는 역할을 수행합니다.
  • DLL의 진입점(DllMain)이 호출되어야 동작이 수행됩니다.

정리

왜 사용자 방식이 작동하지 않는가?

  • DLL 파일은 EXE처럼 독립적으로 실행할 수 없습니다. 단순히 이름을 바꾼다고 해서 실행 파일(EXE)처럼 동작하지 않습니다.

풀이글의 방식은 왜 작동하는가?

  • 풀이글의 방식은 명시적으로 LoadLibrary 함수를 호출하여 DLL을 메모리에 로드하고, 진입점(DllMain)을 실행하도록 했기 때문입니다.

수정된 실행 방법

  1. 아래 코드를 작성하여 prob_rev.dll을 로드하는 프로그램을 만듭니다.
  2. #include <stdio.h> #include <windows.h> int main() { HINSTANCE hinstDLL = LoadLibrary("prob_rev.dll"); if (hinstDLL != NULL) { printf("DLL loaded successfully.\n"); FreeLibrary(hinstDLL); } else { printf("Failed to load DLL.\n"); } return 0; }
  3. 코드를 컴파일하여 EXE 파일로 생성합니다:
  4. gcc -o loader.exe loader.c
  5. DLL과 함께 실행:
  6. loader.exe

이 방식으로 DLL을 정상적으로 로드할 수 있습니다.

 


 

ㅇㅎㅇㅎ dll은 EXE와 달리 독립적으로 실행되지 않으며, 다른 프로그램(EXE 또는 다른 DLL)에 의해 호출되어야 하구나

 

그렇게 비쥬얼코드로 빌드할려는데 어, exe파일 생성됐는데 어 클릭해도 안먹힘ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ

2시간동안..2시간동안...삽질하다가..결국 리눅스로 했다..

 

 

 

 

 

살려줘...왜 난 쉬운길로 안가지는데 ㅠㅜ