ACTF2022 复现

dropper

脱壳 & 多进程

(1) 脱壳

从github.com/upx/upx上下载最新的源码编译并脱壳即可

(2) 分析无壳程序

main函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
__int64 sub_7FF6DCB19470()
{
char *v0; // rdi
__int64 i; // rcx
char v3[32]; // [rsp+0h] [rbp-30h] BYREF
char v4; // [rsp+30h] [rbp+0h] BYREF
HMODULE ModuleHandleW; // [rsp+38h] [rbp+8h]
__int64 v6; // [rsp+58h] [rbp+28h]
__int64 v7; // [rsp+78h] [rbp+48h]
__int64 v8[3]; // [rsp+98h] [rbp+68h]
unsigned int v9; // [rsp+B4h] [rbp+84h]
int ExitCode[9]; // [rsp+D4h] [rbp+A4h] BYREF
HANDLE hHandle[3]; // [rsp+F8h] [rbp+C8h] BYREF
int v12[26]; // [rsp+130h] [rbp+100h] BYREF
int v13; // [rsp+1B4h] [rbp+184h] BYREF

v0 = &v4;
for ( i = 106i64; i; --i )
{
*(_DWORD *)v0 = -858993460;
v0 += 4;
}
sub_7FF6DCB11816((__int64)&unk_7FF6DCB35100);
sub_7FF6DCB113D4();
ModuleHandleW = GetModuleHandleW(0i64);
v6 = qword_7FF6DCB2AA58(ModuleHandleW, 101i64, 256i64);
v7 = qword_7FF6DCB2AA60(ModuleHandleW, v6);
v8[0] = qword_7FF6DCB2AA68(v7);
v9 = qword_7FF6DCB2AA70(ModuleHandleW, v6);
v8[0] = sub_7FF6DCB113D9(v8[0], v9);
ExitCode[0] = 0;
j_memset(hHandle, 0, sizeof(hHandle));
j_memset(v12, 0, sizeof(v12));
LOWORD(v13) = 0;
if ( !(unsigned int)sub_7FF6DCB115C3((int)hHandle, (int)v12, v8[0], (int)&v13, 2ui64) )
{
WaitForSingleObject(hHandle[0], 0xFFFFFFFF);
GetExitCodeProcess(hHandle[0], (LPDWORD)ExitCode);
CloseHandle(hHandle[1]);
CloseHandle(hHandle[0]);
}
sub_7FF6DCB114B0();
sub_7FF6DCB116E0(v3, &unk_7FF6DCB24B30);
return 0i64;
}

sub_7FF6C44D13D4调用了sub_7FF6C44D8860, 可以看到很多LoadLibraryAGetProcAddress,
用于手动加载Windows API.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
FARPROC sub_7FF6C44D8860()
{
// [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

sub_7FF6C44D1816((__int64)&unk_7FF6C44F5100);
v0 = (const CHAR *)sub_7FF6C44D12A8((__int64)&unk_7FF6C44EA000, 13i64);
hModule = LoadLibraryA(v0);
v1 = (const CHAR *)sub_7FF6C44D12A8((__int64)&unk_7FF6C44EA278, 13i64);
qword_7FF6C44EAA50 = (__int64)GetProcAddress(hModule, v1);
v2 = (const CHAR *)sub_7FF6C44D12A8((__int64)&unk_7FF6C44EA2B0, 19i64);
qword_7FF6C44EAAE8 = (__int64)GetProcAddress(hModule, v2);
v3 = (const CHAR *)sub_7FF6C44D12A8((__int64)&unk_7FF6C44EA300, 17i64);
qword_7FF6C44EAA80 = (__int64)GetProcAddress(hModule, v3);
v4 = (const CHAR *)sub_7FF6C44D12A8((__int64)&unk_7FF6C44EA350, 17i64);
qword_7FF6C44EAA88 = (__int64)GetProcAddress(hModule, v4);
v5 = (const CHAR *)sub_7FF6C44D12A8((__int64)&unk_7FF6C44EA3A0, 18i64);
qword_7FF6C44EAAB8 = (__int64)GetProcAddress(hModule, v5);
v6 = (const CHAR *)sub_7FF6C44D12A8((__int64)&unk_7FF6C44EA3F0, 19i64);
qword_7FF6C44EAAC0 = (__int64)GetProcAddress(hModule, v6);
v7 = (const CHAR *)sub_7FF6C44D12A8((__int64)&unk_7FF6C44EA440, 13i64);
qword_7FF6C44EAAA0 = (__int64)GetProcAddress(hModule, v7);
v8 = (const CHAR *)sub_7FF6C44D12A8((__int64)&unk_7FF6C44EA478, 15i64);
qword_7FF6C44EAA48 = (__int64)GetProcAddress(hModule, v8);
v9 = (const CHAR *)sub_7FF6C44D12A8((__int64)&unk_7FF6C44EA070, 14i64);
qword_7FF6C44EAA58 = (__int64 (__fastcall *)(_QWORD, _QWORD, _QWORD))GetProcAddress(hModule, v9);
v10 = (const CHAR *)sub_7FF6C44D12A8((__int64)&unk_7FF6C44EA0A8, 13i64);
qword_7FF6C44EAA60 = (__int64 (__fastcall *)(_QWORD, _QWORD))GetProcAddress(hModule, v10);
v11 = (const CHAR *)sub_7FF6C44D12A8((__int64)&unk_7FF6C44EA0E0, 13i64);
qword_7FF6C44EAA68 = (__int64 (__fastcall *)(_QWORD))GetProcAddress(hModule, v11);
v12 = (const CHAR *)sub_7FF6C44D12A8((__int64)&byte_7FF6C44EA118, 15i64);
qword_7FF6C44EAA70 = (__int64 (__fastcall *)(_QWORD, _QWORD))GetProcAddress(hModule, v12);
v13 = (const CHAR *)sub_7FF6C44D12A8((__int64)&unk_7FF6C44EA158, 15i64);
qword_7FF6C44EAAE0 = (__int64)GetProcAddress(hModule, v13);
v14 = (const CHAR *)sub_7FF6C44D12A8((__int64)&unk_7FF6C44EA4C0, 17i64);
qword_7FF6C44EAAF0 = (__int64)GetProcAddress(hModule, v14);
v15 = (const CHAR *)sub_7FF6C44D12A8((__int64)&unk_7FF6C44EA038, 13i64);
qword_7FF6C44EAA40 = LoadLibraryA(v15);
v16 = (const CHAR *)sub_7FF6C44D12A8((__int64)&unk_7FF6C44EA198, 7i64);
qword_7FF6C44EAA78 = (__int64)GetProcAddress(qword_7FF6C44EAA40, v16);
v17 = (const CHAR *)sub_7FF6C44D12A8((__int64)&unk_7FF6C44EA1B8, 6i64);
qword_7FF6C44EAA90 = (__int64)GetProcAddress(qword_7FF6C44EAA40, v17);
v18 = (const CHAR *)sub_7FF6C44D12A8((__int64)&unk_7FF6C44EA1D0, 8i64);
qword_7FF6C44EAA98 = (__int64)GetProcAddress(qword_7FF6C44EAA40, v18);
v19 = (const CHAR *)sub_7FF6C44D12A8((__int64)&unk_7FF6C44EA1F0, 5i64);
qword_7FF6C44EAAA8 = (__int64)GetProcAddress(qword_7FF6C44EAA40, v19);
v20 = (const CHAR *)sub_7FF6C44D12A8((__int64)&unk_7FF6C44EA208, 6i64);
qword_7FF6C44EAAB0 = (__int64)GetProcAddress(qword_7FF6C44EAA40, v20);
v21 = (const CHAR *)sub_7FF6C44D12A8((__int64)&unk_7FF6C44EA220, 8i64);
qword_7FF6C44EAAC8 = (__int64)GetProcAddress(qword_7FF6C44EAA40, v21);
v22 = (const CHAR *)sub_7FF6C44D12A8((__int64)&unk_7FF6C44EA240, 7i64);
qword_7FF6C44EAAD0 = (__int64)GetProcAddress(qword_7FF6C44EAA40, v22);
v23 = (const CHAR *)sub_7FF6C44D12A8((__int64)&unk_7FF6C44EA260, 5i64);
result = GetProcAddress(qword_7FF6C44EAA40, v23);
qword_7FF6C44EAAD8 = (__int64)result;
return result;
}

加载完Windows API后可以看到使用了FindResourceWWaitForSingleObject,
大概率是将一个程序藏在了.rsrc中然后创建了新进程.

且在sub_7FF6C44D13D9的返回值中发现了MZ头:

接下来可以使用工具(如Resource Hacker)将.rsrc中的PE文件导出并根据上述sub_7FF6C44D13D9函数,对导出的PE文件进行解码:(假设从资源段导出的文件为dropper_rsrc.exe)

1
2
3
4
5
6
7
8
9
filename = 'dropper_rsrc.exe'
output_filename = 'dropper_rsrc_real.exe'
with open(filename, 'rb') as fn, \
open(output_filename, 'wb') as output_fn:
buf = fn.read()
out_buf = [i ^ 0x73 for i in buf]
output_fn.write(bytes(out_buf))
pass

接下来对dropper_rsrc_real.exe进行分析:

得到真正的程序

main函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
// sub_00007FF67D14D080
int __cdecl main(int argc, const char **argv, const char **envp)
{
// [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

v3 = &v14;
for ( i = 0x6BEi64; i; --i )
{
*(_DWORD *)v3 = 0xCCCCCCCC;
v3 += 4;
}
v34 = 0;
sub_7FF67D1417EE((__int64)&unk_7FF67D1660F2);
v35 = GetObfuString((__int64)v20, (__int64)&unk_7FF67D15E168, 5);
v36 = v35;
sub_7FF67D141735(std::cout, v35);
string_destroy_7FF67D14119A((__int64)v20);
sub_7FF67D1417DF(inpStr_v12);
sub_7FF67D141032(std::cin, inpStr_v12);
v35 = string_length((__int64)inpStr_v12);
v5 = string_c_str((__int64)inpStr_v12);
v6 = j_Base64Encode_14001B600(v5, v35);
string_copy_eq((__int64)inpStr_v12, (__int64)v6);
v22 = v21;
v35 = string_copy((__int64)v21, (__int64)inpStr_v12);
To128_7FF67D141244((__int64)v16, v35);
v24 = sub_7FF67D14106E(2016i64);
if ( v24 )
{
v26 = &v25;
v35 = GetObfuString((__int64)v27, (__int64)&unk_7FF67D15F300, 360);
v36 = v35;
v34 |= 1u;
v7 = string_c_str(v35);
v8 = ToW_7FF67D14110E((__int64)v26, v7);
v37 = (void (__fastcall ***)(_QWORD, _QWORD))sub_7FF67D141433(v24, v8);
}
else
{
v37 = 0i64;
}
v23 = v37;
v17 = v37;
if ( (v34 & 1) != 0 )
{
v34 &= ~1u;
string_destroy_7FF67D14119A((__int64)v27);
}
sub_7FF67D141226((__int64)v17); // virtual table changed
v29 = sub_7FF67D14106E(2004i64);
if ( v29 )
v35 = COPY_7FF67D14152D(v29, (__int64)v16);
else
v35 = 0i64;
v28 = v35;
v18 = v35;
(**v17)(v17, v35); // virtual function
SUB_7FF67D14119F(v18, (__int64)v19, (__int64)(v17 + 1));
if ( (unsigned __int8)sub_7FF67D141014((__int64)v19) )
{
v35 = GetObfuString((__int64)v30, (__int64)&unk_7FF67D15F910, 4);
v36 = v35;
v9 = sub_7FF67D141735(std::cout, v35);
std::ostream::operator<<(v9, sub_7FF67D14105A);
string_destroy_7FF67D14119A((__int64)v30);
}
else
{
v35 = GetObfuString((__int64)v31, (__int64)&unk_7FF67D15F920, 5);
v36 = v35;
v10 = sub_7FF67D141735(std::cout, v35);
std::ostream::operator<<(v10, sub_7FF67D14105A);
string_destroy_7FF67D14119A((__int64)v31);
}
v32 = v17;
if ( v17 )
v35 = sub_7FF67D141316(v32, 1i64);
else
v35 = 0i64;
v33 = 0;
string_destroy_7FF67D14119A((__int64)inpStr_v12);
v11 = v33;
stack_check_7FF67D14169F((__int64)v13, (__int64)&unk_7FF67D1593D0);
return v11;
}

程序执行流程总结

(1) 输入字符串

(2) Base64编码 & 10000进制

j_Base64Encode_14001B600函数将输入字符串Base64编码,

随后To128_7FF67D141244函数将Base64编码结果转换为BigInt存储:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// local variable allocation has failed, the output may be wrong!
// local variable allocation has failed, the output may be wrong!
__int64 __fastcall To128_7FF67D14BC50(__int64 a1, __int64 a2)
{
char *v2; // rdi
__int64 i; // rcx
unsigned __int64 v4; // rax
char *v5; // rax
__int64 v6; // rax
char v8[32]; // [rsp+0h] [rbp-20h] BYREF
char v9; // [rsp+20h] [rbp+0h] BYREF
char v10[2036]; // [rsp+30h] [rbp+10h] BYREF
int j; // [rsp+824h] [rbp+804h] OVERLAPPED BYREF
char v12[2048]; // [rsp+850h] [rbp+830h] BYREF
char v13[2048]; // [rsp+1050h] [rbp+1030h] BYREF
char v14[2048]; // [rsp+1850h] [rbp+1830h] BYREF
char v15[3584]; // [rsp+2050h] [rbp+2030h] BYREF
char v16[2024]; // [rsp+2E50h] [rbp+2E30h] BYREF
unsigned __int64 v17; // [rsp+3638h] [rbp+3618h]

v2 = &v9;
for ( i = 3086i64; i; --i )
{
*(_DWORD *)v2 = 0xCCCCCCCC;
v2 += 4;
}
sub_7FF67D1417EE((__int64)&unk_7FF67D1660F2);
sub_7FF67D1414B5((__int64)v10);
for ( j = 0; ; ++j )
{
v17 = j;
v4 = string_length(a2);
if ( v17 >= v4 )
break;
ToW_7FF67D1416E5((__int64)v12, 128i64);
POW_7FF67D141578((__int64)v12, (__int64)v13, (__int64)&j);
v5 = (char *)string_charAt_7FF67D141118(a2, j);
ToW_7FF67D1416E5((__int64)v14, (unsigned int)*v5);
MUL_7FF67D14132F((__int64)v14, (__int64)v15, (__int64)v13);
v6 = ADD_7FF67D141857((__int64)v10, (__int64)v16, (__int64)v15);
COPY_7FF67D1410A0((__int64)v10, v6);
}
sub_7FF67D14152D(a1, (__int64)v10);
string_destroy_7FF67D14119A(a2);
stack_check_7FF67D14169F((__int64)v8, (__int64)&unk_7FF67D159290);
return a1;
}

To128_7FF67D14BC50也就是相当于:

1
2
3
a1 = 0
for idx, val in enumerate(a2):
a1 = a1 + (ord(val) * (128 ** idx))

(3) 对上一步得到的10000进制BigInt进行加法、减法、乘法的操作

在此之前,sub_7FF67D141226会对BigInt类的virtual function table进行更改, 如下图:
左半部分为正常控制流, 但是其中会故意出发除0异常,
异常处理函数让控制流从右侧lea r8, sub_7FF67D14187F的代码块开始执行,
而其中sub_7FF67D14182A会修改vftable, 从而对类对象调用方法进行Hook.

因此, 我们进入sub_7FF67D14187F中, 即可发现加密函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
__int64 __fastcall sub_7FF67D14C6F0(__int64 a1, __int64 inpStr_a2)
{
// [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

v2 = &v26;
for ( i = 10918i64; i; --i )
{
*(_DWORD *)v2 = 0xCCCCCCCC;
v2 += 4;
}
sub_7FF67D1417EE((__int64)&unk_7FF67D1660F2);
v58 = GetObfuString((__int64)v38, (__int64)&unk_7FF67D15E680, 80);// 64584540291872516627894939590684951703479643371381420434698676192916126802789388
v59 = v58;
v4 = string_c_str(v58);
ToW_7FF67D14110E((__int64)v27, v4);
string_destroy_7FF67D14119A((__int64)v38);
v58 = GetObfuString((__int64)v39, (__int64)&unk_7FF67D15E7C0, 80);// 11783410410469738048283152171898507679537812634841032055361622989575562121323526
v59 = v58;
v5 = string_c_str(v58);
ToW_7FF67D14110E((__int64)v28, v5);
string_destroy_7FF67D14119A((__int64)v39);
v58 = GetObfuString((__int64)v40, (__int64)&unk_7FF67D15E900, 80);// 55440851777679184418972581091796582321001517732868509947716453414109025036506793
v59 = v58;
v6 = string_c_str(v58);
ToW_7FF67D14110E((__int64)v29, v6);
string_destroy_7FF67D14119A((__int64)v40);
v58 = GetObfuString((__int64)v41, (__int64)&unk_7FF67D15EA40, 80);// 17867047589171477574847737912328753108849304549280205992204587760361310317983607
v59 = v58;
v7 = string_c_str(v58);
ToW_7FF67D14110E((__int64)v30, v7);
string_destroy_7FF67D14119A((__int64)v41);
v58 = GetObfuString((__int64)v42, (__int64)&unk_7FF67D15EB80, 80);// 07537302706582391238853817483600228733479333152488218477840149847189049516952787
v59 = v58;
v8 = string_c_str(v58);
ToW_7FF67D14110E((__int64)v31, v8);
string_destroy_7FF67D14119A((__int64)v42);
v58 = GetObfuString((__int64)v43, (__int64)&unk_7FF67D15ECC0, 80);// 80793226935699295824618519685638809874579343342564712419235587177713165502121664
v59 = v58;
v9 = string_c_str(v58);
ToW_7FF67D14110E((__int64)v32, v9);
string_destroy_7FF67D14119A((__int64)v43);
v58 = GetObfuString((__int64)v44, (__int64)&unk_7FF67D15EE00, 80);// 14385283226689171523445844388769467232023411467394422980403729848631619308579599
v59 = v58;
v10 = string_c_str(v58);
ToW_7FF67D14110E((__int64)v33, v10);
string_destroy_7FF67D14119A((__int64)v44);
v58 = GetObfuString((__int64)v45, (__int64)&unk_7FF67D15EF40, 80);// 55079029772840138145785005601340325789675668817561045403173659223377346727295749
v59 = v58;
v11 = string_c_str(v58);
ToW_7FF67D14110E((__int64)v34, v11);
string_destroy_7FF67D14119A((__int64)v45);
v58 = GetObfuString((__int64)v46, (__int64)&unk_7FF67D15F080, 80);// 71119332457202863671922045224905384620742912949065190274173724688764272313900465
v59 = v58;
v12 = string_c_str(v58);
ToW_7FF67D14110E((__int64)v35, v12);
string_destroy_7FF67D14119A((__int64)v46);
v58 = GetObfuString((__int64)v47, (__int64)&unk_7FF67D15F1C0, 80);// 57705573952449699620072104055030025886984180500734382250587152417040141679598894
v59 = v58;
v13 = string_c_str(v58);
ToW_7FF67D14110E((__int64)v36, v13);
string_destroy_7FF67D14119A((__int64)v47);
COPY_7FF67D14152D((__int64)v37, inpStr_a2);
v14 = ADD_7FF67D141857(v37, v48, v27);
COPY_7FF67D1410A0((__int64)v37, v14);
v15 = MUL_7FF67D14132F(v37, v49, v28);
COPY_7FF67D1410A0((__int64)v37, v15);
v16 = SUB_7FF67D14119F(v37, v50, v29);
COPY_7FF67D1410A0((__int64)v37, v16);
v17 = ADD_7FF67D141857(v37, v51, v30);
COPY_7FF67D1410A0((__int64)v37, v17);
v18 = MUL_7FF67D14132F(v37, v52, v31);
COPY_7FF67D1410A0((__int64)v37, v18);
v19 = SUB_7FF67D14119F(v37, v53, v32);
COPY_7FF67D1410A0((__int64)v37, v19);
v20 = ADD_7FF67D141857(v37, v54, v33);
COPY_7FF67D1410A0((__int64)v37, v20);
v21 = SUB_7FF67D14119F(v37, v55, v34);
COPY_7FF67D1410A0((__int64)v37, v21);
v22 = ADD_7FF67D141857(v37, v56, v35);
COPY_7FF67D1410A0((__int64)v37, v22);
v23 = SUB_7FF67D14119F(v37, v57, v36);
COPY_7FF67D1410A0((__int64)v37, v23);
COPY_7FF67D1410A0(inpStr_a2, (__int64)v37);
return stack_check_7FF67D14169F((__int64)v25, (__int64)&unk_7FF67D158F30);
}

该函数中依然使用GetObfuString对混淆的字符串进行解密, 解密的结果是许多非常大的十进制数,
ToW_7FF67D14110E会将其转换为10000进制: 每四个10进制数字为一组,组合成一个10000进制数字, 每组最小为0000, 最大为9999, 所以可以理解为10000进制.如10进制128转换为10000进制就是0128, 10进制1239999转换为10000进制就是0123_9999.

sub_7FF67D14C6F0调用10000进制的加减乘法, 即ADD、SUB、MUL进行计算,并将结果返回.

(4) 判断最终结果是否为0

调用完sub_7FF67D14C6F0返回到main函数, 还会调用一次SUB_7FF67D14119F,
用来将计算结果与一个固定的数进行剑法操作, 通过动态调试可以发现,固定的数是834572051814337070469744559761199605121805728622619480039894407167152612470842477813941120780374570205930952883661000998715107231695919001238818879944773516507366865633886966330912156402063735306303966193481658066437563587241718036562480496368592194719092339868512773222711600878782903109949779245500098606570248830570792028831133949440164219842871034275938433.

最后sub_7FF67D141014用来判断最终计算结果是否为0.

Script

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
n = 834572051814337070469744559761199605121805728622619480039894407167152612470842477813941120780374570205930952883661000998715107231695919001238818879944773516507366865633886966330912156402063735306303966193481658066437563587241718036562480496368592194719092339868512773222711600878782903109949779245500098606570248830570792028831133949440164219842871034275938433
n += 57705573952449699620072104055030025886984180500734382250587152417040141679598894
n -= 71119332457202863671922045224905384620742912949065190274173724688764272313900465
n += 55079029772840138145785005601340325789675668817561045403173659223377346727295749
n -= 14385283226689171523445844388769467232023411467394422980403729848631619308579599
n += 80793226935699295824618519685638809874579343342564712419235587177713165502121664
n //= 7537302706582391238853817483600228733479333152488218477840149847189049516952787
n -= 17867047589171477574847737912328753108849304549280205992204587760361310317983607
n += 55440851777679184418972581091796582321001517732868509947716453414109025036506793
n //= 11783410410469738048283152171898507679537812634841032055361622989575562121323526
n -= 64584540291872516627894939590684951703479643371381420434698676192916126802789388

flag = []

while n > 0:
flag.append(n % 128)
n = n // 128

flag = ''.join(list(map(chr, flag)))
import base64
print(base64.b64decode(flag))