수호의 메모장
[dreamhack, rev] Permpkin writeup 본문
https://dreamhack.io/wargame/challenges/981
Permpkin
Description chall 바이너리를 실행하여 플래그를 어떠한 연산을 거쳐 나온 결과를 flag1.txt와 flag2.txt로 저장하였습니다. 사용자는 chall 을 실행하여 sample flag를 연산한 후 rev1.txt와 rev2.txt 파일을 생성
dreamhack.io
IDA로 main 함수를 열어보면 아래와 같이 되어 있다:
__int64 __fastcall main(int a1, char **a2, char **a3)
{
size_t v3; // rbx
size_t v4; // rbx
char v6[32]; // [rsp+0h] [rbp-B0h] BYREF
char v7[32]; // [rsp+20h] [rbp-90h] BYREF
char v8[32]; // [rsp+40h] [rbp-70h] BYREF
char s[24]; // [rsp+60h] [rbp-50h] BYREF
FILE *v10; // [rsp+78h] [rbp-38h]
int v11; // [rsp+84h] [rbp-2Ch]
FILE *stream; // [rsp+88h] [rbp-28h]
int v13; // [rsp+90h] [rbp-20h]
int k; // [rsp+94h] [rbp-1Ch]
int j; // [rsp+98h] [rbp-18h]
int i; // [rsp+9Ch] [rbp-14h]
strcpy(s, "_this_is_sample_flag_");
strcpy(v8, "this_is_sample_flag");
strcpy(v7, "CC2A750B63821F45AC20839");
for ( i = 0; i <= 22; ++i )
v6[i] = sub_126E((unsigned int)v7[i]);
v13 = strlen(s);
sub_11FD(s, 0LL, (unsigned int)(v13 - 1), v6);
sub_12E7(s, v6);
stream = fopen("rev1.txt", "wb");
for ( j = 0; ; ++j )
{
v3 = j;
if ( v3 >= strlen(s) )
break;
fprintf(stream, "%d ", (unsigned int)s[j]);
}
fclose(stream);
v11 = strlen(v8);
sub_11FD(v8, 0LL, (unsigned int)(v11 - 1), v6);
sub_12E7(v8, v6);
v10 = fopen("rev2.txt", "wb");
for ( k = 0; ; ++k )
{
v4 = k;
if ( v4 >= strlen(v8) )
break;
fprintf(v10, "%d ", (unsigned int)v8[k]);
}
fclose(v10);
return 0LL;
}
핵심만 보자:
이를 라벨링 해준다
구조가 좀 보이는가?
enc1는 아래와 같이 생겼다:
sub_11C9는 swap 함수이다.
enc2는 아래와 같다:
__int64 __fastcall enc2(const char *a1, const char *a2)
{
__int64 result; // rax
int v3; // [rsp+14h] [rbp-Ch]
int v4; // [rsp+18h] [rbp-8h]
int j; // [rsp+1Ch] [rbp-4h]
signed int k; // [rsp+1Ch] [rbp-4h]
unsigned int i; // [rsp+1Ch] [rbp-4h]
v4 = strlen(a2);
v3 = strlen(a1);
if ( v3 <= v4 )
{
for ( i = 0; ; ++i )
{
result = i;
if ( (int)i >= v3 )
break;
a1[i] ^= a2[i];
}
}
else
{
for ( j = 0; j < v4; ++j )
a1[j] ^= a2[j];
for ( k = v4; ; ++k )
{
result = (unsigned int)k;
if ( k >= v3 )
break;
a1[k] ^= a2[k % v4];
}
}
return result;
}
enc2의 경우 간단한 XOR 연산을 취하고 있는 함수이기에 암호문과 키를 그대로 다시 넣어주면 역산이 된다.
enc1의 역산만 구현해 주면 풀 수 있다.
code:
#include <Windows.h>
#include <iostream>
using namespace std;
short unsigned int ctype_b_values[] = {
0x0002, //
0x0002, //
0x0002, //
0x0002, //
0x0002, //
0x0002, //
0x0002, //
0x0002, //
0x0002, //
0x2003, //
0x2002, //
0x2002, //
0x2002, //
0x2002, //
0x0002, //
0x0002, //
0x0002, //
0x0002, //
0x0002, //
0x0002, //
0x0002, //
0x0002, //
0x0002, //
0x0002, //
0x0002,
0x0002,
0x0002,
0x0002, //
0x0002, //
0x0002, //
0x0002, //
0x0002, //
0x6001, //
0xc004, //!
0xc004, //"
0xc004, //#
0xc004, //$
0xc004, //%
0xc004, //&
0xc004, //'
0xc004, //(
0xc004, //)
0xc004, //*
0xc004, //+
0xc004, //,
0xc004, //-
0xc004, //.
0xc004, ///
0xd808, //0
0xd808, //1
0xd808, //2
0xd808, //3
0xd808, //4
0xd808, //5
0xd808, //6
0xd808, //7
0xd808, //8
0xd808, //9
0xc004, //:
0xc004, //;
0xc004, //<
0xc004, //=
0xc004, //>
0xc004, //?
0xc004, //@
0xd508, //A
0xd508, //B
0xd508, //C
0xd508, //D
0xd508, //E
0xd508, //F
0xc508, //G
0xc508, //H
0xc508, //I
0xc508, //J
0xc508, //K
0xc508, //L
0xc508, //M
0xc508, //N
0xc508, //O
0xc508, //P
0xc508, //Q
0xc508, //R
0xc508, //S
0xc508, //T
0xc508, //U
0xc508, //V
0xc508, //W
0xc508, //X
0xc508, //Y
0xc508, //Z
0xc004, //[
0xc004, //
0xc004, //]
0xc004, //^
0xc004, //_
0xc004, //`
0xd608, //a
0xd608, //b
0xd608, //c
0xd608, //d
0xd608, //e
0xd608, //f
0xc608, //g
0xc608, //h
0xc608, //i
0xc608, //j
0xc608, //k
0xc608, //l
0xc608, //m
0xc608, //n
0xc608, //o
0xc608, //p
0xc608, //q
0xc608, //r
0xc608, //s
0xc608, //t
0xc608, //u
0xc608, //v
0xc608, //w
0xc608, //x
0xc608, //y
0xc608, //z
0xc004, //{
0xc004, //|
0xc004, //}
0xc004, //~
0x0002, //
0x0000, //€
0x0000, //
0x0000, //‚
0x0000, //ƒ
0x0000, //„
0x0000, //…
0x0000, //†
0x0000, //‡
0x0000, //ˆ
0x0000, //‰
0x0000, //Š
0x0000, //‹
0x0000, //Œ
0x0000, //
0x0000, //Ž
0x0000, //
0x0000, //
0x0000, //‘
0x0000, //’
0x0000, //“
0x0000, //”
0x0000, //•
0x0000, //–
0x0000, //—
0x0000, //˜
0x0000, //™
0x0000, //š
0x0000, //›
0x0000, //œ
0x0000, //
0x0000, //ž
0x0000, //Ÿ
0x0000, //
0x0000, //¡
0x0000, //¢
0x0000, //£
0x0000, //¤
0x0000, //¥
0x0000, //¦
0x0000, //§
0x0000, //¨
0x0000, //©
0x0000, //ª
0x0000, //«
0x0000, //¬
0x0000, //
0x0000, //®
0x0000, //¯
0x0000, //°
0x0000, //±
0x0000, //²
0x0000, //³
0x0000, //´
0x0000, //µ
0x0000, //¶
0x0000, //·
0x0000, //¸
0x0000, //¹
0x0000, //º
0x0000, //»
0x0000, //¼
0x0000, //½
0x0000, //¾
0x0000, //¿
0x0000, //À
0x0000, //Á
0x0000, //Â
0x0000, //Ã
0x0000, //Ä
0x0000, //Å
0x0000, //Æ
0x0000, //Ç
0x0000, //È
0x0000, //É
0x0000, //Ê
0x0000, //Ë
0x0000, //Ì
0x0000, //Í
0x0000, //Î
0x0000, //Ï
0x0000, //Ð
0x0000, //Ñ
0x0000, //Ò
0x0000, //Ó
0x0000, //Ô
0x0000, //Õ
0x0000, //Ö
0x0000, //×
0x0000, //Ø
0x0000, //Ù
0x0000, //Ú
0x0000, //Û
0x0000, //Ü
0x0000, //Ý
0x0000, //Þ
0x0000, //ß
0x0000, //à
0x0000, //á
0x0000, //â
0x0000, //ã
0x0000, //ä
0x0000, //å
0x0000, //æ
0x0000, //ç
0x0000, //è
0x0000, //é
0x0000, //ê
0x0000, //ë
0x0000, //ì
0x0000, //í
0x0000, //î
0x0000, //ï
0x0000, //ð
0x0000, //ñ
0x0000, //ò
0x0000, //ó
0x0000, //ô
0x0000, //õ
0x0000, //ö
0x0000, //÷
0x0000, //ø
0x0000, //ù
0x0000, //ú
0x0000, //û
0x0000, //ü
0x0000, //ý
0x0000, //þ
0x0000, //ÿ
0x0020, //
0x0000, //
0x0000, //
0x0000, //
0x0000, //
0x0000, //
0x0028, //
0x0000, //
0x0043, //
0x0000, //
0x0029, //
0x0000, //
0x0000, //
0x0000,
0x0000, //
0x0000, //
0x003c, //
0x0000, //
0x003c, //
0x0000, //
0x0000, //
0x0000, //
0x0000, //
0x0000,
0x002d,
0x0000,
0x0000,
0x0000,
0x0000,
0x0000, //
0x0028, //
0x0000, //
0x0052, //
0x0000, //!
0x0029, //"
0x0000, //#
0x0000, //$
0x0000, //%
0x0000, //&
0x0000, //'
0x0075, //(
0x0000, //)
0x0000, //*
0x0000, //+
0x0000, //,
0x0000, //-
0x002c, //.
0x0000, ///
0x0000, //0
0x0000, //1
0x0000, //2
0x0000, //3
0x003e, //4
0x0000, //5
0x003e, //6
0x0000, //7
0x0000, //8
0x0000, //9
0x0000, //:
0x0000, //;
0x0020, //<
0x0000, //=
0x0031, //>
0x0000, //?
0x002f, //@
0x0000, //A
0x0034, //B
0x0000, //C
0x0020, //D
0x0000, //E
0x0000, //F
0x0000, //G
0x0000, //H
0x0000, //I
0x0020, //J
0x0000, //K
0x0031, //L
0x0000, //M
0x002f, //N
0x0000, //O
0x0032, //P
0x0000, //Q
0x0020, //R
0x0000, //S
0x0000, //T
0x0000, //U
0x0000, //V
0x0000, //W
0x0020, //X
0x0000, //Y
0x0033, //Z
0x0000, //[
0x002f,
0x0000, //]
0x0034, //^
0x0000, //_
0x0020, //`
0x0000, //a
0x0000, //b
0x0000, //c
0x0000, //d
0x0000, //e
0x0041, //f
0x0000, //g
0x0045, //h
0x0000, //i
0x0000, //j
0x0000, //k
0x0000, //l
0x0000, //m
0x0078, //n
0x0000, //o
0x0000, //p
0x0000, //q
0x0000, //r
0x0000, //s
0x0073, //t
0x0000, //u
0x0073, //v
0x0000, //w
0x0000, //x
0x0000, //y
0x0000, //z
0x0000, //{
0x0061, //|
0x0000, //}
0x0065, //~
0x0000, //
};
const short unsigned int** __ctype_b_loc()
{
static short unsigned int** ret = 0;
if (ret != 0)
{
return (const short unsigned int**)ret;
}
int len = sizeof(ctype_b_values) / sizeof(short unsigned int);
int i;
short unsigned int* lookupTable = (short unsigned int*)malloc(len * sizeof(short unsigned int));
for (i = 0; i < len; i++)
{
lookupTable[i] = ctype_b_values[i];
}
ret = (short unsigned int**)malloc(sizeof(short unsigned int*));
*ret = lookupTable;
return (const short unsigned int**)ret;
}
__int64 __fastcall sub_126E(unsigned int a1)
{
unsigned int v2; // [rsp+1Ch] [rbp-4h]
v2 = 0;
if (((*__ctype_b_loc())[a1] & 0x800) != 0)
{
return a1 - 40;
}
else if (a1 > 0x45)
{
if (a1 > 0x4F)
{
if (a1 <= 0x59)
return a1 - 80;
}
else
{
return a1 - 70;
}
}
else
{
return a1 - 60;
}
return v2;
}
char* __fastcall swap(char* a1, char* a2)
{
char* result; // rax
char v3; // [rsp+1Fh] [rbp-1h]
v3 = *a1;
*a1 = *a2;
result = a2;
*a2 = v3;
return result;
}
size_t __fastcall enc1(char *a1, __int64 a2, __int64 a3, const char* a4)
{
size_t result; // rax
int i; // [rsp+2Ch] [rbp-14h]
for (i = 0; ; ++i)
{
result = strlen(a4);
if (i >= result)
break;
swap(a1, a1 + a4[i]);
}
return result;
}
__int64 __fastcall enc2(char* a1, char* a2)
{
__int64 result; // rax
signed int v3; // [rsp+14h] [rbp-Ch]
signed int v4; // [rsp+18h] [rbp-8h]
int j; // [rsp+1Ch] [rbp-4h]
signed int k; // [rsp+1Ch] [rbp-4h]
unsigned int i; // [rsp+1Ch] [rbp-4h]
v4 = strlen(a2);
v3 = strlen(a1);
if (v3 <= v4)
{
for (i = 0; ; ++i)
{
result = i;
if ((int)i >= v3)
break;
a1[i] ^= a2[i];
}
}
else
{
for (j = 0; j < v4; ++j)
a1[j] ^= a2[j];
for (k = v4; ; ++k)
{
result = (unsigned int)k;
if (k >= v3)
break;
a1[k] ^= a2[k % v4];
}
}
return result;
}
size_t __fastcall dec1(char* a1, __int64 a2, __int64 a3, const char* a4)
{
size_t result; // rax
int i; // [rsp+2Ch] [rbp-14h]
result = strlen(a4);
for (i = result - 1; i >= 0; --i) // Start from the end of a4 and move backwards
{
swap(a1, a1 + a4[i]); // Undo the swap
}
return result;
}
void get_flag()
{
char key_initialized[32]; // [rsp+0h] [rbp-B0h] BYREF
char key[32]; // [rsp+20h] [rbp-90h] BYREF
char plain_2[32]; // [rsp+40h] [rbp-70h] BYREF
char plain_1[24]; // [rsp+60h] [rbp-50h] BYREF
int plain_strlen; // [rsp+90h] [rbp-20h]
string flag = "flag{";
strcpy(key, "CC2A750B63821F45AC20839");
for (int i = 0; i <= 22; ++i)
key_initialized[i] = sub_126E(key[i]);
char encrypted[] = { 102, 111, 62, 107, 104, 52,100, 96, 103, 104, 79, 61, 126, 111, 88, 57, 90, 60, 108, 61, 127 };
enc2(encrypted, key_initialized);
plain_strlen = strlen(encrypted);
dec1(encrypted, 0LL, (unsigned int)(plain_strlen - 1), key_initialized);
cout << encrypted << endl;
flag += encrypted;
char encrypted2[] = { 52, 50, 99, 104, 127, 127, 120, 89, 122, 84, 121, 107, 124, 115, 52, 102, 104, 63, 99 };
enc2(encrypted2, key_initialized);
plain_strlen = strlen(encrypted2);
dec1(encrypted2, 0LL, (unsigned int)(plain_strlen - 1), key_initialized);
cout << encrypted2 << endl;
flag += encrypted2;
flag += "}";
cout << flag;
}
int main()
{
get_flag();
return 0;
}
'Security > Reverse Engineering' 카테고리의 다른 글
Easy_ELF [KUCC 정뾰 과제] (0) | 2023.10.10 |
---|---|
code2 [KUCC 정뾰 세션 과제] (0) | 2023.10.10 |
Let's break 010Editor's License Authentication! (0) | 2023.09.20 |
NtQuerySystemInformation API Hooking을 통한 Usermode Process Hiding (0) | 2022.10.11 |