Introduction
1월에 Insomni’hack Teaser CTF에 참여했다.
대회 때 못 풀었던 TrompeLoeil를 upsolve해 보았다.
Reversing - TrompeLoeil
1
2
$ file Trompe-Loeil.dll
Trompe-Loeil.dll: PE32+ executable (DLL) (console) x86-64 Mono/.Net assembly, for MS Windows
1
2
3
4
5
6
7
8
$ ./Trompe-Loeil.exe
Guess the flag:
123
Checking.
Checking..
Checking...
Checking....
Nope!
Main
1
2
3
4
5
6
7
8
9
10
11
12
// Trompe_Loeil.M
// Token: 0x0600002A RID: 42 RVA: 0x0000E004 File Offset: 0x0000E004
private static void Main(string[] args)
{
Console.WriteLine("Guess the flag:");
if (M.ComputeSha256Hash(Console.ReadLine()) == "49156db8ffcbf419b5777c28339b75ad6aaae115e3b5678437c10c2e4fb9e9f0")
{
Console.WriteLine("Congratz!");
return;
}
Console.Write("Nope!");
}
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
// Token: 0x0600002A RID: 42 RVA: 0x0000E004 File Offset: 0x0000E004
.method private hidebysig static
void Main (
string[] args
) cil managed
{
// Header Size: 12 bytes
// Code Size: 75 (0x4B) bytes
// LocalVarSig Token: 0x1100000F RID: 15
.maxstack 2
.entrypoint
.locals init (
[0] string
)
/* 0x0000E010 72611C0070 */ IL_0000: ldstr "Guess the flag:"
/* 0x0000E015 285000000A */ IL_0005: call void [System.Console]System.Console::WriteLine(string)
/* 0x0000E01A 285100000A */ IL_000A: call string [System.Console]System.Console::ReadLine()
/* 0x0000E01F 00 */ IL_000F: nop
/* 0x0000E020 00 */ IL_0010: nop
/* 0x0000E021 00 */ IL_0011: nop
/* 0x0000E022 00 */ IL_0012: nop
/* 0x0000E023 00 */ IL_0013: nop
/* 0x0000E024 00 */ IL_0014: nop
/* 0x0000E025 00 */ IL_0015: nop
/* 0x0000E026 00 */ IL_0016: nop
/* 0x0000E027 00 */ IL_0017: nop
/* 0x0000E028 00 */ IL_0018: nop
/* 0x0000E029 00 */ IL_0019: nop
/* 0x0000E02A 00 */ IL_001A: nop
/* 0x0000E02B 00 */ IL_001B: nop
/* 0x0000E02C 00 */ IL_001C: nop
/* 0x0000E02D 00 */ IL_001D: nop
/* 0x0000E02E 00 */ IL_001E: nop
/* 0x0000E02F 00 */ IL_001F: nop
/* 0x0000E030 00 */ IL_0020: nop
/* 0x0000E031 00 */ IL_0021: nop
/* 0x0000E032 00 */ IL_0022: nop
/* 0x0000E033 00 */ IL_0023: nop
/* 0x0000E034 2828000006 */ IL_0024: call string Trompe_Loeil.M::ComputeSha256Hash(string)
/* 0x0000E039 72E51C0070 */ IL_0029: ldstr "49156db8ffcbf419b5777c28339b75ad6aaae115e3b5678437c10c2e4fb9e9f0"
/* 0x0000E03E 285300000A */ IL_002E: call bool [System.Runtime]System.String::op_Equality(string, string)
/* 0x0000E043 2C0B */ IL_0033: brfalse.s IL_0040
/* 0x0000E045 72681D0070 */ IL_0035: ldstr "Congratz!"
/* 0x0000E04A 285000000A */ IL_003A: call void [System.Console]System.Console::WriteLine(string)
/* 0x0000E04F 2A */ IL_003F: ret
/* 0x0000E050 727C1D0070 */ IL_0040: ldstr "Nope!"
/* 0x0000E055 285400000A */ IL_0045: call void [System.Console]System.Console::Write(string)
/* 0x0000E05A 2A */ IL_004A: ret
} // end of method M::Main
이상하게 dnSpy로 열어보면
Main 함수에 sha256 계산하는 부분만 있고 Checking
을 출력하는 부분이 없다.
x64dbg로 해당 부분을 찾아봤더니 nop
가 다른 instruction들로 채워져있었다.
Reversing R2R stomped binary
R2R stomping에 대한 설명은 이 글에 자세히 적혀있다.
글을 참고해서 dotPeek으로 ReadyToRun
헤더를 확인하고 ILSpy로 분석을 시작했다.
Analysis
ILSpy를 이용해 열어보면
아래처럼 ReadyToRun native code를 확인할 수 있다.
native code를 보면서 x64dbg로 디버깅해보면 어렵지 않게 루틴을 파악할 수 있다.
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
...
; IL_0413
0000000000004554 488B0D6D820000 mov rcx,[rel 0`C7C8h];
000000000000455B 488B31 mov rsi,[rcx];;
000000000000455E 488BCE mov rcx,rsi;;
0000000000004561 488BD5 mov rdx,rbp;
0000000000004564 FF150E7D0000 call qword [rel 0`C278h] ; string [System.Runtime]System.String::Join(string, class [System.Runtime]System.Collections.Generic.IEnumerable`1<string>) // 이상한 16진수 숫자들 join함 (고정)
000000000000456A 488BC8 mov rcx,rax;
000000000000456D FF157D7E0000 call qword [rel 0`C3F0h] ; string Trompe_Loeil.M::ComputeSha256Hash(string) // join한 문자열로 sha256 계산
0000000000004573 488BF8 mov rdi,rax; // 비교대상이 여기에서 세팅됨
; IL_0424
0000000000004576 FF157C7C0000 call qword [rel 0`C1F8h] ; System.Collections.Generic.List`1<string> (NEW_OBJECT)
000000000000457C 488BE8 mov rbp,rax;
000000000000457F 488BCD mov rcx,rbp;;
0000000000004582 FF15A07D0000 call qword [rel 0`C328h] ; void System.Collections.Generic.List`1<__Canon>..ctor() (METHOD_ENTRY)
; IL_042e
0000000000004588 4533F6 xor r14d,r14d;
; IL_045c
000000000000458B 448B7B08 mov r15d,[rbx+8]; rbx = Local 6 // user input
000000000000458F 4585FF test r15d,r15d
0000000000004592 7E47 jle short 0000`0000`0000`45DBh // 입력 끝에 도달하면 sha256 계산하는 부분으로 이동
; IL_0433
0000000000004594 418BCE mov ecx,r14d;
0000000000004597 0FB74C4B0C movzx ecx,word [rbx+rcx*2+0Ch];; rbx = Local 6; // input에서 한 글자씩 가져옴
000000000000459C 894C2420 mov [rsp+20h],ecx
; IL_043e
00000000000045A0 488D4C2420 lea rcx,[rsp+20h];
00000000000045A5 FF15E57C0000 call qword [rel 0`C290h] ; instance string [System.Runtime]System.Char::ToString()
00000000000045AB 488BC8 mov rcx,rax;
00000000000045AE FF15747E0000 call qword [rel 0`C428h] ; class Trompe_Loeil.C Trompe_Loeil.S::F7(string) // 인자로 한 글자가 들어감. 뭔가 복잡한 연산을 하지만 같은 글자면 같은 output이 나옴
00000000000045B4 488BC8 mov rcx,rax;
00000000000045B7 4C8D1DDA7A0000 lea r11,[rel 0`C098h] // hex to string
00000000000045BE 3909 cmp [rcx],ecx;
00000000000045C0 41FF13 call qword [r11]
00000000000045C3 488BD0 mov rdx,rax
00000000000045C6 488BCD mov rcx,rbp;; rbp = Local 4
00000000000045C9 4C8D1D807B0000 lea r11,[rel 0`C150h]
00000000000045D0 41FF13 call qword [r11]
; IL_0456
00000000000045D3 41FFC6 inc r14d; r14 = Local 7
; IL_045c
00000000000045D6 453BFE cmp r15d,r14d
00000000000045D9 7FB9 jg short 0000`0000`0000`4594h // 입력 길이만큼 loop
; IL_0467
00000000000045DB 488BCE mov rcx,rsi;;
00000000000045DE 488BD5 mov rdx,rbp;
00000000000045E1 FF15917C0000 call qword [rel 0`C278h] ; string [System.Runtime]System.String::Join(string, class [System.Runtime]System.Collections.Generic.IEnumerable`1<string>) // 내 입력의 hash값을 join (0x~~0x~~)
00000000000045E7 488BC8 mov rcx,rax;
00000000000045EA FF15007E0000 call qword [rel 0`C3F0h] ; string Trompe_Loeil.M::ComputeSha256Hash(string) // join한 문자열로 sha256 계산
00000000000045F0 488BC8 mov rcx,rax;
00000000000045F3 488BD7 mov rdx,rdi; // rdx는 처음에 ComputeSha256Hash로 계산한 값 (고정)
00000000000045F6 4C8D1DA37A0000 lea r11,[rel 0`C0A0h]
00000000000045FD 3909 cmp [rcx],ecx;
00000000000045FF 41FF13 call qword [r11] // stepinto로 들어가보니 rcx랑 rdx랑 비교함
; Epilog
0000000000004602 90 nop
0000000000004603 4883C428 add rsp,28h
0000000000004607 5B pop rbx;
0000000000004608 5D pop rbp;
0000000000004609 5E pop rsi;
000000000000460A 5F pop rdi;
000000000000460B 415E pop r14;
000000000000460D 415F pop r15
000000000000460F C3 ret
정리하면 아래와 같다
1
2
3
4
5
6
res = M::ComputeSha256Hash("join된 hex값")
lst = []
for c in ipt:
lst.append(hex(Trompe_Loeil.S::F7(c)))
check res == M::ComputeSha256Hash(''.join(lst))
solution
ComputeSha256Hash
함수에 특이한 부분이 안 보여서
Trompe_Loeil.S::F7
의 리턴값으로 res
계산에 사용되는 hex값을 생성할 수 있을 것이라 생각하고
아래 코드를 작성하였다.
stage1.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import string
from winpwn import *
context.windbg = "C:\\Users\\zzre\\AppData\\Local\\Microsoft\\WindowsApps\\WinDbgX.exe"
p = process([".\\Trompe-Loeil.exe"])
script = '''
bp Trompe_Loeil+0x456A ".printf \\"%mu\\n\\", @rax+0xc;";
bp Trompe_Loeil+0x45E7 ".printf \\"%mu\\n\\", @rax+0xc;";
'''
p.recvuntil('Guess the flag:')
p.sendline(string.printable.strip())
windbg.attach(p, script=script) # attach 후 go로 breakpoint에 진입해 비교 문자열 획득
p.close()
sol.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import re
import string
split = lambda x: re.findall('0x.{16}', x)
target = '0x5800FF34666A237551656C5A5B604463595E62585A5C4C5E5C5B6056595B4F5D5B5B5D565A59525B0x2B43FF266D33001C454047122733181F2B3B46211E28242C2A2E3D2B25242230302C342A2927212E0x4F02FF3063680065635F6344595E26515E5F5A42555D384D595C5A425059404E555958454F54454F0x304EFF444536002C2F264C252B2B1730322E412B2C2D2031312F3A2B2C2E2431312F382C2C2E27310x35A4FE4F580E00123B3649343C2D1B2B3D3B3D323731232F3C3C3A31353228303B3A393034342B320x2F3CFF234A1A002A3B385231342B173136373E2F302C1E303634392D302C23303533362C2F2C262F0x4E97FF5C523200374E51634E54492F485754574A514B384956545249504D3E4A565451494F4E414C0x4924FF3758510054555161445250264B555153424F4F3248535050414D4F394951504F414B4C3D480x2C2EFE33533200282523412831311B2F2E2937282E2E202E2F2B33282D2D222D2E2B31282C2C242D0x7D0898A413FF009AC338C5428BA334968D76925E879751848C7A8E6284925E81877D8B68808F65810x4800FF266B52155A4F53594751522D5050514E454D4F364B514F4D434D4D3A494E4E4B444D4B3F480x7D0898A413FF009AC338C5428BA334968D76925E879751848C7A8E6284925E81877D8B68808F65810x35A4FE4F580E00123B3649343C2D1B2B3D3B3D323731232F3C3C3A31353228303B3A393034342B320x3A04FE2850480049383C5338404322433F3D46373E3F2A3F403C42373D3E2F3E403D40363D3D313C0x4597FF46471000284B51644C483B283E4D4E5246453E31414D4D4D44444036434D4B4A42444139440x7D0898A413FF009AC338C5428BA334968D76925E879751848C7A8E6284925E81877D8B68808F65810x4E55FF455D560042625E6F3C4A592F454F586945444E3F514E4E5F4D4A493F54554D554C4E4C3E510x4E97FF5C523200374E51634E54492F485754574A514B384956545249504D3E4A565451494F4E414C0x402EFF25472A003F3A4D604848412D4444474F42413F334244444940403F37424443473F3F3F39420x5CBBFF3C3800154D78949371533B364E6474756454484656656D6D5F554D4E5A666A685D554F515C0x2F3CFF234A1A002A3B385231342B173136373E2F302C1E303634392D302C23303533362C2F2C262F0x55C2FF4C5F002228596A72685948404B5961605B534B46505A5E5B57534D4B525A5D5955524E4D530x7D0898A413FF009AC338C5428BA334968D76925E879751848C7A8E6284925E81877D8B68808F65810x4E97FF5C523200374E51634E54492F485754574A514B384956545249504D3E4A565451494F4E414C0x55C2FF4C5F002228596A72685948404B5961605B534B46505A5E5B57534D4B525A5D5955524E4D530x4E00FF325D6409675756644A56582D575A555848555538515953544854553E50575453485253424F0x7D0898A413FF009AC338C5428BA334968D76925E879751848C7A8E6284925E81877D8B68808F65810x4F02FF3063680065635F6344595E26515E5F5A42555D384D595C5A425059404E555958454F54454F0x4314FF33595400504D485A3C4C4D23464D4A4E3B484C2F424B494C3A464A364349494B3B44473A430x7D0898A413FF009AC338C5428BA334968D76925E879751848C7A8E6284925E81877D8B68808F65810x35A4FE4F580E00123B3649343C2D1B2B3D3B3D323731232F3C3C3A31353228303B3A393034342B320x4E00FF325D6409675756644A56582D575A555848555538515953544854553E50575453485253424F0x4E97FF5C523200374E51634E54492F485754574A514B384956545249504D3E4A565451494F4E414C0x4924FF3758510054555161445250264B555153424F4F3248535050414D4F394951504F414B4C3D480x2C2EFE33533200282523412831311B2F2E2937282E2E202E2F2B33282D2D222D2E2B31282C2C242D0x7D0898A413FF009AC338C5428BA334968D76925E879751848C7A8E6284925E81877D8B68808F65810x4800FF266B52155A4F53594751522D5050514E454D4F364B514F4D434D4D3A494E4E4B444D4B3F480x7D0898A413FF009AC338C5428BA334968D76925E879751848C7A8E6284925E81877D8B68808F65810x63DEFF505E001B397B8B8172654D3E53737D706763574A586F766A61615A525C6E726860605B575F0x3E8CFF3568002822445154493B2F2E37414A49433A34343B414646403A36373C4144443F3A38393D0x4E97FF5C523200374E51634E54492F485754574A514B384956545249504D3E4A565451494F4E414C0x3F15FE2C4B44004A47445C3E4144204548424D3C414229424741483B41422F424642453A404032410x4DDFFF5B49000D21445B62514032303F4D5A5A51463D3E465156574E464142495054534C4643454B0x4661FE543645003B4F3973404149234A46435D3F4444334947465441434438494746504243453B49'
target = split(target)
arr = '0x4314FF33595400504D485A3C4C4D23464D4A4E3B484C2F424B494C3A464A364349494B3B44473A430x5000FF296358226A465F635350553F5B4F585B514E5246565154584F4F5049545153564E4F4F4B520x4800FF266B52155A4F53594751522D5050514E454D4F364B514F4D434D4D3A494E4E4B444D4B3F480x4E00FF325D6409675756644A56582D575A555848555538515953544854553E50575453485253424F0x4E97FF5C523200374E51634E54492F485754574A514B384956545249504D3E4A565451494F4E414C0x5826FF374B58006C696E79575C592D5A656466525C5B3D57636161515A5B455862615F5058594A580x4633FF33483E004D4E526646494627494E4F5644484732474E4C5042474738484D4C4E4146453C470x3C66FF2B8416002B53583A3C523B162E525336354B4222304E51383346412A31494C393443412F350x4937FF334E4100525B5B68484E47234A565456454D493048545251434C4A374853514F424A493C480x5E71FF574C4E005868697D5C665C365868666B58635F455A67666657605F4C5B656564575E5F515D0x3C17FF25493B00493F465A3C3E3D214242424B3B3D3C2A3F4240453A3D3C2F40424043393C3B323E0x4A21FF2A46420057525C6B4D4D4C294F52555A494C4C354D525255474B4C3C4D515152464A4A404C0x3905FF1D463C004B3B465A3B3B3C21423D404A3A3A3A2A3E3E3D45383A3A2E3E3E3D41363A38323C0x4924FF3758510054555161445250264B555153424F4F3248535050414D4F394951504F414B4C3D480x2F3CFF234A1A002A3B385231342B173136373E2F302C1E303634392D302C23303533362C2F2C262F0x569EFF352C0800506C8D8D6951392F4A606C6F5C50443E51606666585149465560646156504B4A560x3F15FE2C4B44004A47445C3E4144204548424D3C414229424741483B41422F424642453A404032410x4A9EFF4646110030585E6B514B3C27415558594B4B42334454555347494539465353504648463E480x327AFF33710025112E38423E372E2B2D31373836322F2D3033363734312F2F3134353633312F30320x493AFF55305F004759347C41425624514D406541455032504C445C42464D394F4C455743464C3C4E0x33A0FF444D000011333A4B3835261C2A383A3F34332B242E39393A33322D28303938393332302B330x3E8CFF3568002822445154493B2F2E37414A49433A34343B414646403A36373C4144443F3A38393D0x5482FF51573F003E6963744C59592F485C62684A5157424F575D644F4F52485458585E52525148570x4597FF46471000284B51644C483B283E4D4E5246453E31414D4D4D44444036434D4B4A42444139440x3A14FF22493800473D45583A3C3A20403F4148393A39283D3F3E43383A3A2E3D403E41373A38303B0x4E1BFF35435400604E59714E5251305552535E4C4F4F3B525352584B4F5041525352554A4E4E44500x4010FF2D484A00504646603F434523484744503E42422D4547434A3D434232454743473C424035430x55C2FF4C5F002228596A72685948404B5961605B534B46505A5E5B57534D4B525A5D5955524E4D530x402EFF25472A003F3A4D604848412D4444474F42413F334244444940403F37424443473F3F3F39420x5CBBFF3C3800154D78949371533B364E6474756454484656656D6D5F554D4E5A666A685D554F515C0x3A04FE2850480049383C5338404322433F3D46373E3F2A3F403C42373D3E2F3E403D40363D3D313C0x2137FE1E590E0017192631252720132021242821221F182124232620221E1A202322241F211F1B200x3658FE37562500293F3C4E333C351B313D3D4231383725333C3D3E3136362B343B3B3C3235362D360x3382FE384F06001A353F4B3A34291A2B383A3F34342D2430393A3A33332F28313839383232312A330x2C2EFE33533200282523412831311B2F2E2937282E2E202E2F2B33282D2D222D2E2B31282C2C242D0x5600FF28635C2376596F6D5B55583C5F5A6062585757475B5C5D5E5657574A5A5B5B5B5457554E580x4571FF4966350033594C583D52471F3A53504C394C4A2E3B4F504C3A474A363E4A4E4B3D45483B410x4D69FF4D513F00465155654B524A2B4856535847514C374A555454474F4E3D4B535452484E4E424C0x3F1CFF2D584600494849573B4746214248484A3A44452D3F47464839424433404545463A4141363F0x4124FF2E5D4700454C4D59394A4C243F484D4F38434A323F45494D393F45374142454A3C3F413A420x5571FF474A34004A5866715A585332545D626356575540535E5E5E52565445545B5D5C5156544B540x63DEFF505E001B397B8B8172654D3E53737D706763574A586F766A61615A525C6E726860605B575F0x5326FF4357670060625A6E485C5E2D545E5D6048575D3C515A5B5E48545A445257595C4A535649530x5A7AFF615C6100446A6279455969384C5A65734B50614B56565D6F545159505D595968585658525F0x5800FF34666A237551656C5A5B604463595E62585A5C4C5E5C5B6056595B4F5D5B5B5D565A59525B0x6100FF49658B077D6A6373556D7338686D6668546A6E47626B666656676C4E6268666458656953610x40AFFF474C02001D46515D4843322434484C4D4140382E39474A483F3F3A343B4748463E3E3C363F0x4400FE2251490B57414F5E46444A2C4E464B52454448354B48494E444447394A47484B4345453D470x4E55FF455D560042625E6F3C4A592F454F586945444E3F514E4E5F4D4A493F54554D554C4E4C3E510x2B43FF266D33001C454047122733181F2B3B46211E28242C2A2E3D2B25242230302C342A2927212E0x4741FF3B6C54003F575A61364D572D3E49555C3D434E3E47494B574445473C4A4B494F4449473E480x60FFFD68560015275F73766D5F4B4250676F6A655F534C57676B64605D5651596669635F5E59555C0x69AAFF5D634E00487F8C8C5C6B6F46556C7E8462626858646D737A67666659676F72736569685F680x35A4FE4F580E00123B3649343C2D1B2B3D3B3D323731232F3C3C3A31353228303B3A393034342B320x4F02FF3063680065635F6344595E26515E5F5A42555D384D595C5A425059404E555958454F54454F0x5665FF4D7452004C6D686548655D2E4A65665E4A5C5B3E4F61605A4E5A584353625C57505A5745550x422EFF355B4D00444E4F5F38474E273E464D5539404936414447523D3E43394444444C3F40413B440x3B42FF325533003842465436403B2037414448353C3B2B373F414436393B313A3F3F4236383A323B0x3D49FF357554002D464B55283F45233642484A2F3E4630353D474B34373F373D3D3F46393B3C353E0x3B79FE386A1A00234D4E4938443A1A2E484C43333F3E2833444A43353B3D2E36414541373A3C31390x4F91FE444A2100445E6D6D504F3E2A455C635F4D4E47384A5A605A4C4C483E4B575B574C4C4A434E0x480DFF1B6E41004E5162514853572547515D4D424D55364550574F424A513B474C534E444A4D41480x4DDFFF5B49000D21445B62514032303F4D5A5A51463D3E465156574E464142495054534C4643454B0x85FFA44101003A92DBF2D39356384675A6BEB4926D575E7C9CACA48C72646B8299A29A87746B73860x3A45FF366C41002B4C464F293D48223041454E2F36402D373C3F4834373C303A3E3C4335383B313B0x5028FF384A5400605E5E704C535129535C59604B535237515A575A4A52523E515856574A515043510x3549FE327334002943434329423E1D293D423F29363B292E383D3E2E34362D3338393B3134342D350x4B44FF41514A005056556747524C294B57535845504E344A555353454D4E3B4B535351454C4D404B0x82E38A2C001A6DCBFFEDA24810195BB0E9E7AE5F2725579ED3D7AB6B3B365D98C3C7A36D464467980x3941FF3842350039383B5A373837223B3B3B4B3737372B3B3B3B453736382F3C3C3B42373638313B0x4935FF4A3359005053417841434E27514C476242464A344F4C49594446493A4E4C49554546493E4E0x84FF943C0B002F97EDF3BE8759353B7CBEC7A6886D504E7EB1B69A85755E5B81AAAB9181776664840x45FEDD703C00020D36465749402E2E3242484E454037383C46494B45413B3C4047494A46423F3F430x8B00D29938FF25C48A63C163979B6EA483819E7C8F957B98888497828C9380948A8594858B9282920x36FFE782560F0E0022253E3237262C2634323B32332A2E2D35353933332D2F2F35353734333031320x8D00FF4CA59E6ABB69A981958C928A9688948B928B9489948A928C918C928A938A918C908C918B910x3158FF1C75001F223449383F302A1F2C373C3534322B252D38393532332D292F38383331322F2A300x4D58FF147B004D426F7F7771504A3C4A515F5F5B504A494D55595A544E4A494E535655514C494A4E0x8112FF4F3A9E00C758B0A181926E737E7D8B8C84807D7583808889827F7F7884818687817F7F7B840x3AEBFF746309120021263C3235282C2C38394038372E313139393D36373034333A393C37373335360x1F5EFF246B0024123528361B190D0B1924292B211C16141D2426261F1C17171D2523241D1B19171F0x4ADFFF60640026144A5063554A3B383C484F544E483F40434B4F514C484244464C4E504C494546490x3BB5FF4A5D0005163F45473D3A281C314547403B3D30273548473F3B3D332A3644453C3B3E382F390x5A49FF416C6500556577734A5B643D515E656D53585C465A616063535C5C4857606261525A5C50580x4639FE4831510048553D76413D4D224D4C4262404248304C4A4558414247364B4A4554414247394B0x4677FF434026003D50556948443925434F4F5845443E30454E4E5045444036464E4C4D44444239470x4241FF473548003F4F3A6D41394A20464B3C5D3E3D462B47483F543D3E4432474740503E3F4435470x758E075CC8670075FEA11455C6760360EDAB2250C0851153D8AC2F4DB68D2451C5A83B4EA98E35550x7D0898A413FF009AC338C5428BA334968D76925E879751848C7A8E6284925E81877D8B68808F65810x80DE8B1F00287BD8FFDC862801257AD5FCDB862C062779D1F8D987300A2A79CEF3D48633102E7ACA0x304EFF444536002C2F264C252B2B1730322E412B2C2D2031312F3A2B2C2E2431312F382C2C2E27310x3F43FF3B3E3A00424043643C3D3A25414142523C3C3B2F4141424C3C3C3C34414141483C3C3C36410x4661FE543645003B4F3973404149234A46435D3F4444334947465441434438494746504243453B490x81E6FF773234005B8C99B18D847452768B9095818079637A8C8D8F7D7F7A6A7C888B897C7F7C737F'
arr = split(arr)
lst = string.printable.strip()
flag = ''
for x in target:
flag += lst[arr.index(x)]
print(flag)
flag : INS{Re4dy_2_Run_M4ster_4r3_S0_R34dy_2_Fl4g!}
후기
PE 리버싱을 많이 안 해봐서 대회 때 겁먹고 런했는데
풀어보니까 할만한 것 같다..!
올해는 PE 리버싱도 많이 풀어봐야겠다 ㅎㅎ