리버스 엔지니어링 오픈채팅방에 크랙미가 올라와서 한번 분석해봤습니다.

PE32+ executable (GUI) x86-64, for MS Windows
풀이는 동적 트레이스 분석만으로 진행하였습니다.

입력을 하고 확인을 누르면 틀렸습니다. 가 출력됩니다.

해당 문자열을 검색해서 이를 쓰는 부분을 찾아줬습니다.

24C2에서 이쪽으로 넘어오네요.

1E140에서 값을 읽어서 -1면 틀렸습니다.가 출력됩니다.


코드를 패치해서 확인해보니 eax가 1이 되면 정답입니다!가 출력됩니다.

1E140에 값을 쓰는 부분을 찾았습니다.
ctf.exe+45F26 - movzx eax,al
ctf.exe+45F29 - dec eax
ctf.exe+45F2B - or eax,01
ctf.exe+45F2E - mov [ctf.exe+1E140],eax
좀 더 코드를 넓혀서 확인해 보겠습니다.
ctf.exe+45ECC - jmp ctf.exe+21020
ctf.exe+45ED1 - call qword ptr [ctf.exe+17030] { ->GDI32.CreateSolidBrush }
ctf.exe+45ED7 - push 000000A2 { 162 }
ctf.exe+45EDC - push 38A7F542 { 0.00 }
ctf.exe+45EE1 - jmp ctf.exe+21020
ctf.exe+45EE6 - nop
ctf.exe+45EE7 - push 000015B5 { 5557 }
ctf.exe+45EEC - push 7D30E1C1 { 2100355521 }
ctf.exe+45EF1 - jmp ctf.exe+21020
ctf.exe+45EF6 - push rbp
ctf.exe+45EF7 - sub rsp,30 { 48 }
ctf.exe+45EFB - lea rbp,[rsp+30]
ctf.exe+45F00 - test byte ptr [rdx+13],18 { 24 }
ctf.exe+45F04 - mov eax,[rcx]
ctf.exe+45F06 - je ctf.exe+45F17
ctf.exe+45F08 - push 0000155D { 5469 }
ctf.exe+45F0D - push 1A489D63 { 440966499 }
ctf.exe+45F12 - jmp ctf.exe+21020
ctf.exe+45F17 - push 0000155F { 5471 }
ctf.exe+45F1C - push FFFFFFFFB30B38B5 { -1291110219 }
ctf.exe+45F21 - jmp ctf.exe+21020
ctf.exe+45F26 - movzx eax,al
ctf.exe+45F29 - dec eax
ctf.exe+45F2B - or eax,01 { 1 }
ctf.exe+45F2E - mov [ctf.exe+1E140],eax { (-1) }
ctf.exe+45F34 - mov rcx,[rsp+00000088]
ctf.exe+45F3C - xor edx,edx
ctf.exe+45F3E - xor r8d,r8d
ctf.exe+45F41 - push 0000015E { 350 }
ctf.exe+45F46 - push 393F40DA { 218 }
ctf.exe+45F4B - jmp ctf.exe+21020
ctf.exe+45F50 - mov r8,[rsi+20]
ctf.exe+45F54 - test r8,r8
ctf.exe+45F57 - je ctf.exe+45F68
ctf.exe+45F59 - push 00000B04 { 2820 }
ctf.exe+45F5E - push 2CB70E82 { 750194306 }
ctf.exe+45F63 - jmp ctf.exe+21020
ctf.exe+45F68 - push 00000B06 { 2822 }
ctf.exe+45F6D - push FFFFFFFF861770D4 { -2045284140 }
ctf.exe+45F72 - jmp ctf.exe+21020
ctf.exe+45F77 - mov rcx,[ctf.exe+1E170] { (0) }
ctf.exe+45F7E - lea rdx,[ctf.exe+17F9F] { ("SymGetSearchPathW") }
ctf.exe+45F85 - push 0000063B { 1595 }
ctf.exe+45F8A - push 51322B33 { "3+2Q" }
ctf.exe+45F8F - jmp ctf.exe+21020
ctf.exe+45F94 - mov bl,[rbp-08]
ctf.exe+45F97 - push 00000D7A { 3450 }
ctf.exe+45F9C - push 06DCB353 { 115127123 }
ctf.exe+45FA1 - jmp ctf.exe+21020
ctf.exe+45FA6 - mov ebx,eax
ctf.exe+45FA8 - test eax,eax
ctf.exe+45FAA - jne ctf.exe+45FBB
ctf.exe+45FAC - push 000004D3 { 1235 }
ctf.exe+45FB1 - push 244A6873 { "shJ$" }
ctf.exe+45FB6 - jmp ctf.exe+21020
전체적으로 push - push - jmp 21020이 반복되며 흐름이 결정됩니다.
ctf.exe+21020 - pushfq
ctf.exe+21021 - push rax
ctf.exe+21022 - push rcx
ctf.exe+21023 - push r10
ctf.exe+21025 - push r11
ctf.exe+21027 - mov r10,[rsp+30]
ctf.exe+2102C - cmp r10,000017C8 { 6088 }
ctf.exe+21033 - mov ecx,00000000 { 0 }
ctf.exe+21038 - cmovae r10,rcx
ctf.exe+2103C - mov r11,[rsp+28]
ctf.exe+21041 - lea rax,[ctf.exe+21080] { (-1455347649) }
ctf.exe+21048 - mov ecx,[rax+r10*4]
ctf.exe+2104C - lea eax,[r10+r11]
ctf.exe+21050 - xor eax,960A9336 { -1777691850 }
ctf.exe+21056 - xor ecx,eax
ctf.exe+21058 - lea rax,[ctf.exe+21000] { (1423976) }
ctf.exe+2105F - add rax,rcx
ctf.exe+21062 - mov [rsp+30],rax
ctf.exe+21067 - pop r11
ctf.exe+21069 - pop r10
ctf.exe+2106B - pop rcx
ctf.exe+2106C - pop rax
ctf.exe+2106D - popfq
ctf.exe+2106E - lea rsp,[rsp+08]
ctf.exe+21073 - ret
21020은 값을 받아서 복호화한 오프셋으로 넘어가는 점프테이블 방식으로 흐름을 바꿉니다.
버튼 클릭시 어디로 처음 흐름이 변하는지 추적했습니다.
R10=FF table=DABDC028 ret=4CB7A26F offset=F070 target=140030070
mov [rsp+00000088],rcx
mov edx,000003E9
R10=100 table=BEE062E ret=9DE7AC96 offset=3388E target=14005488E
call qword ptr [1400171F0]

이제 여기서부터 따라가보겠습니다.
mov [rsp+00000088],rcx
mov edx,000003E9
call qword ptr [1400171F0] ; { ->USER32.GetDlgItem }
xorps xmm0,xmm0
movaps [rsp+00000200],xmm0
movaps [rsp+000001F0],xmm0
movaps [rsp+000001E0],xmm0
movaps [rsp+000001D0],xmm0
movaps [rsp+000001C0],xmm0
movaps [rsp+000001B0],xmm0
movaps [rsp+000001A0],xmm0
movaps [rsp+00000190],xmm0
movaps [rsp+00000180],xmm0
movaps [rsp+00000170],xmm0
movaps [rsp+00000160],xmm0
movaps [rsp+00000150],xmm0
movaps [rsp+00000140],xmm0
movaps [rsp+00000130],xmm0
movaps [rsp+00000120],xmm0
movaps [rsp+00000110],xmm0
lea rdi,[rsp+00000110]
mov rcx,rax
mov rdx,rdi
mov r8d,00000080
call qword ptr [1400171E8] ; { ->USER32.GetWindowTextW }
movsxd rbx,eax
cmp ebx,00000081 ; input length
jae 1400367D1
mov qword ptr [rsp+70],00000000
mov qword ptr [rsp+78],00000001
mov qword ptr [rsp+00000080],00000000
mov rax,rbx
shr rax,1
mov r8d,ebx
and r8d,01
add r8,rax
jne 14003206D
mov qword ptr [rsp+20],00000001
lea rcx,[rsp+70]
mov r9d,00000001
xor edx,edx
call 140055B84
push rsi
push rdi
sub rsp,48
add rdx,r8
jb ctf.exe+55B9E
mov rsi,rcx
mov rcx,[rsp+00000080]
mov rax,[rsi]
lea rdi,[rax+rax]
cmp rdx,rdi
cmova rdi,rdx
xor edx,edx
cmp rcx,01
sete dl
lea rdx,[rdx*4+00000004]
cmp rdi,rdx
cmovbe rdi,rdx
mov r8,[rsi+08]
mov [rsp+28],rcx
mov [rsp+20],r9
lea rcx,[rsp+30]
mov rdx,rax
mov r9,rdi
call 1400278D5
rcx input ptr rdx length r8 =F88302800001E000
ctf.exe+56BD3 - push rsi
ctf.exe+56BD4 - push rdi
ctf.exe+56BD5 - push rbp
ctf.exe+56BD6 - push rbx
ctf.exe+56BD7 - sub rsp,58
ctf.exe+56BDB - mov rsi,rcx
ctf.exe+56BDE - lea rax,[rcx+rdx] ; end ptr + 1
ctf.exe+56BE2 - test rdx,rdx
ctf.exe+56BE5 - je ctf.exe+56BF6 ; not jumped
ctf.exe+56BE7 - push 00000007
ctf.exe+56BEC - push FFFFFFFF9F95B5B7
ctf.exe+56BF1 - jmp ctf.exe+21020
->
ctf.exe+4AE67 - mov r8,[ctf.exe+1E078]
ctf.exe+4AE6E - xor edx,edx
ctf.exe+4AE70 - mov rcx,rsi ; input ptr
ctf.exe+4AE73 - push 0000000C
ctf.exe+4AE78 - push 047FF5B2
ctf.exe+4AE7D - jmp ctf.exe+21020
->
ctf.exe+41A96 - mov r10,rcx
ctf.exe+41A99 - mov rdi,rdx
ctf.exe+41A9C - movzx ecx,byte ptr [rcx] ; input
ctf.exe+41A9F - movzx r9d,cl
ctf.exe+41AA3 - test r9b,r9b
->
ctf.exe+555B6 - lea rcx,[r10+01] ; next ptr
->
ctf.exe+40556 - mov rdx,rcx
ctf.exe+40559 - sub rdx,r10
ctf.exe+4055C - add rdx,rdi
ctf.exe+4055F - lea r10d,[r9-09] ; char - 9
ctf.exe+40563 - cmp r10d,05
ctf.exe+40567 - jb ctf.exe+40578
->
ctf.exe+3DCD1 - cmp r9d,20
ctf.exe+3DCD5 - je ctf.exe+3DCE6
ctf.exe+3DCD7 - push 00000016
ctf.exe+3DCDC - push FFFFFFFFC46336BF
ctf.exe+3DCE1 - jmp ctf.exe+21020
ctf.exe+3DCE6 - push 0000000B
ctf.exe+3DCEB - push FFFFFFFFD0DF6A4B
ctf.exe+3DCF0 - jmp ctf.exe+21020
->
ctf.exe+29201 - cmp r9d,00000085
ctf.exe+29208 - jb ctf.exe+29219
ctf.exe+2920A - push 00000017
ctf.exe+2920F - push FFFFFFFFB8935F26
ctf.exe+29214 - jmp ctf.exe+21020
ctf.exe+29219 - push 00000021
ctf.exe+2921E - push 290F1320
ctf.exe+29223 - jmp ctf.exe+21020
->
ctf.exe+279C7 - cmp rcx,rax ; end == cur
ctf.exe+279CA - je ctf.exe+279DB
ctf.exe+279CC - push 00000022
ctf.exe+279D1 - push 508940CB
ctf.exe+279D6 - jmp ctf.exe+21020
ctf.exe+279DB - push 0000003E
ctf.exe+279E0 - push FFFFFFFFCF8C3489
ctf.exe+279E5 - jmp ctf.exe+21020
-> ..
ctf.exe+3A84D - mov r9,rax
ctf.exe+3A850 - movsx r10d,byte ptr [rax-01] ; next ptr
ctf.exe+3A855 - test r10d,r10d
ctf.exe+3A858 - push 00000028
ctf.exe+3A85D - push 44DBCBF0
ctf.exe+3A862 - jmp ctf.exe+21020
->
ctf.exe+32449 - js ctf.exe+3245A
ctf.exe+3244B - push 00000029
ctf.exe+32450 - push FFFFFFFF977B8CDB
ctf.exe+32455 - jmp ctf.exe+21020
ctf.exe+3245A - push 0000002C
ctf.exe+3245F - push FFFFFFFF92150154
ctf.exe+32464 - jmp ctf.exe+21020
->
ctf.exe+521CF - lea rax,[r9-01]
ctf.exe+521D3 - lea r11d,[r10-09]
ctf.exe+521D7 - cmp r11d,05
ctf.exe+521DB - jb ctf.exe+521EC
ctf.exe+521DD - push 0000002A
ctf.exe+521E2 - push FFFFFFFFE9B8B582
ctf.exe+521E7 - jmp ctf.exe+21020
ctf.exe+521EC - push 00000026
ctf.exe+521F1 - push FFFFFFFF99B8EB2E
ctf.exe+521F6 - jmp ctf.exe+21020
->
ctf.exe+4ED7A - cmp r10d,20
ctf.exe+4ED7E - je ctf.exe+4ED8F
ctf.exe+4ED80 - push 00000034
ctf.exe+4ED85 - push FFFFFFFFF816F58F
ctf.exe+4ED8A - jmp ctf.exe+21020
ctf.exe+4ED8F - push 00000026
ctf.exe+4ED94 - push FFFFFFFF99B8EB2E
ctf.exe+4ED99 - jmp ctf.exe+21020
->
ctf.exe+50034 - cmp r10d,00000085
ctf.exe+5003B - jb ctf.exe+5004C
ctf.exe+5003D - push 00000035
ctf.exe+50042 - push FFFFFFFF8FE17B36
ctf.exe+50047 - jmp ctf.exe+21020
ctf.exe+5004C - push 0000003D
ctf.exe+50051 - push 1A4213EE
ctf.exe+50056 - jmp ctf.exe+21020
->
ctf.exe+3C5E7 - sub rdx,rcx
ctf.exe+3C5EA - add rdx,r9
->
ctf.exe+3C4E9 - sub rdx,rdi
ctf.exe+3C4EC - cmp rdx,1D
->
ctf.exe+52D9E - xor eax,eax
->
함수 ret
->
ctf.exe+45F26 - movzx eax,al
ctf.exe+45F29 - dec eax
ctf.exe+45F2B - or eax,01
처음에 찾은 eax를 설정하는 실패 분기까지 도달했습니다.
cmp rdx,1D에서 넘어오면 실패 분기로 넘어옵니다.
rdx가 입력 글자수 이므로 rdx == 0x1D (29) 임을 알 수 있습니다.

더 진행해보겠습니다.
ctf.exe+3C4F2 - push 0000003F
ctf.exe+3C4F7 - push FFFFFFFFFD01AF30
ctf.exe+3C4FC - jmp ctf.exe+21020<
->
ctf.exe+3B531 - lea rcx,[rsp+40]
- dump rcx
>> 0015F3C0 01 00 00 00 00 00 00 00 31 32 33 34 35 36 37 38 00 00 41 00 00 00 00 00 C0 A6 4B 00 00 00 00 00
ctf.exe+3B536 - call ctf.exe+4C178
-> ctf.exe+331AD - mov ecx,0000002D
ctf.exe+331B2 - mov edx,00000001
-> ctf.exe+41DEC - push rbp
ctf.exe+41DED - push rsi
ctf.exe+41DEE - push rdi
ctf.exe+41DEF - sub rsp,20
ctf.exe+41DF3 - lea rbp,[rsp+20]
ctf.exe+41DF8 - cmp rdx,11
ctf.exe+41DFC - jae ctf.exe+41E0D
ctf.exe+41DFE - push 000002F1
ctf.exe+41E03 - push FFFFFFFFCF6B7CA0
ctf.exe+41E08 - jmp ctf.exe+21020
ctf.exe+41E0D - push 000002F2
ctf.exe+41E12 - push FFFFFFFF80AAE34B
ctf.exe+41E17 - jmp ctf.exe+21020
-> ctf.exe+32750 - xor edx,edx
ctf.exe+32752 - mov r8,rcx
ctf.exe+32755 - add rsp,20
ctf.exe+32759 - pop rdi
ctf.exe+3275A - pop rsi
ctf.exe+3275B - pop rbp
->
ctf.exe+28A37 - push rbp
ctf.exe+28A38 - push rsi
ctf.exe+28A39 - push rdi
ctf.exe+28A3A - sub rsp,20
ctf.exe+28A3E - lea rbp,[rsp+20]
ctf.exe+28A43 - mov rsi,r8
ctf.exe+28A46 - mov edi,edx
->
ctf.exe+2E265 - call qword ptr [ctf.exe+170C0]
->
ctf.exe+3F5EA - test rax,rax
ctf.exe+3F5ED - je ctf.exe+3F5FE
->
ctf.exe+3F6DC - mov rcx,rax
ctf.exe+3F6DF - mov edx,edi
ctf.exe+3F6E1 - mov r8,rsi
ctf.exe+3F6E4 - add rsp,20
ctf.exe+3F6E8 - pop rdi
ctf.exe+3F6E9 - pop rsi
ctf.exe+3F6EA - pop rbp
->
ctf.exe+50E61 - jmp qword ptr [ctf.exe+17088] { ->ntdll.RtlAllocateHeap }
->
ctf.exe+31B43 - test rax,rax
ctf.exe+31B46 - je ctf.exe+31B57
->
ctf.exe+45106 - mov r13,rax
ctf.exe+45109 - mov qword ptr [rsp+30],0000002D { 45 }
ctf.exe+45112 - mov [rsp+38],rax
ctf.exe+45117 - mov qword ptr [rsp+40],00000000 { 0 }
ctf.exe+45120 - xor edi,edi
ctf.exe+45122 - mov rbx,CC23D026C46D750B { -949.83 }
ctf.exe+4512C - mov r14,AB6CB2AB4C6FF956 { 1282406742 }
ctf.exe+45136 - lea r15,[rsp+30]
ctf.exe+4513B - xor r12d,r12d
ctf.exe+4513E - nop dword ptr [rax+rax+00000000]
->
ctf.exe+2C08E - mov rcx,rbx
ctf.exe+2C091 - mov rdx,rdi
ctf.exe+2C094 - call ctf.exe+4CCBD
->
ctf.exe+4CCBD - mov rax,9E3779B97F4A7C15 { 21 }
ctf.exe+4CCC7 - imul rdx,rax
ctf.exe+4CCCB - add rcx,rax
ctf.exe+4CCCE - add rcx,rdx
->
ctf.exe+30159 - mov rax,rcx
ctf.exe+3015C - shr rax,1E { 30 }
ctf.exe+30160 - xor rax,rcx
ctf.exe+30163 - mov rcx,BF58476D1CE4E5B9 { 0.00 }
ctf.exe+3016D - imul rcx,rax
ctf.exe+30171 - mov rax,rcx
ctf.exe+30174 - shr rax,1B { 27 }
ctf.exe+30178 - xor rax,rcx
ctf.exe+3017B - mov rcx,94D049BB133111EB { 321982955 }
ctf.exe+30185 - imul rcx,rax
ctf.exe+30189 - mov rax,rcx
ctf.exe+3018C - shr rax,1F { 31 }
ctf.exe+30190 - xor rax,rcx
ctf.exe+30193 - ret
->
ctf.exe+4B8B3 - mov rbp,rax
ctf.exe+4B8B6 - mov rcx,r14
ctf.exe+4B8B9 - mov rdx,rdi
ctf.exe+4B8BC - call ctf.exe+4CCBD
->
ctf.exe+4CCBD - mov rax,9E3779B97F4A7C15 { 21 }
ctf.exe+4CCC7 - imul rdx,rax
ctf.exe+4CCCB - add rcx,rax
ctf.exe+4CCCE - add rcx,rdx
->
ctf.exe+30159 - mov rax,rcx
ctf.exe+3015C - shr rax,1E { 30 }
ctf.exe+30160 - xor rax,rcx
ctf.exe+30163 - mov rcx,BF58476D1CE4E5B9 { 0.00 }
ctf.exe+3016D - imul rcx,rax
ctf.exe+30171 - mov rax,rcx
ctf.exe+30174 - shr rax,1B { 27 }
ctf.exe+30178 - xor rax,rcx
ctf.exe+3017B - mov rcx,94D049BB133111EB { 321982955 }
ctf.exe+30185 - imul rcx,rax
ctf.exe+30189 - mov rax,rcx
ctf.exe+3018C - shr rax,1F { 31 }
ctf.exe+30190 - xor rax,rcx
ctf.exe+30193 - ret
->
ctf.exe+3D3BE - mov rcx,[rsp+30] ; 2d
ctf.exe+3D3C3 - sub rcx,r12
ctf.exe+3D3C6 - cmp rcx,07 { 7 }
ctf.exe+3D3CA - jna ctf.exe+3D3DB
ctf.exe+3D3CC - push 0000018A { 394 }
ctf.exe+3D3D1 - push FFFFFFFF8CA3020B { -1935474165 }
ctf.exe+3D3D6 - jmp ctf.exe+21020
ctf.exe+3D3DB - push 0000018D { 397 }
ctf.exe+3D3E0 - push FFFFFFFFF2D39684 { -221014396 }
ctf.exe+3D3E5 - jmp ctf.exe+21020
->
ctf.exe+2A014 - mov [r13+r12+00],rbp
ctf.exe+2A019 - add r12,08 { 8 }
ctf.exe+2A01D - mov [rsp+40],r12
ctf.exe+2A022 - mov rcx,[rsp+30]
ctf.exe+2A027 - sub rcx,r12
ctf.exe+2A02A - cmp rcx,07 { 7 }
->
ctf.exe+500A7 - mov r13,[rsp+38]
ctf.exe+500AC - mov [r13+r12+00],rax
ctf.exe+500B1 - inc rdi
ctf.exe+500B4 - cmp r12,15 { 21 }
ctf.exe+500B8 - lea r12,[r12+08]
ctf.exe+500BD - mov [rsp+40],r12
->
ctf.exe+2C08E - mov rcx,rbx
ctf.exe+2C091 - mov rdx,rdi
ctf.exe+2C094 - call ctf.exe+4CCBD
->
ctf.exe+4CCBD - mov rax,9E3779B97F4A7C15 { 21 }
ctf.exe+4CCC7 - imul rdx,rax
ctf.exe+4CCCB - add rcx,rax
ctf.exe+4CCCE - add rcx,rdx
-> ... ->
ctf.exe+31490 - mov rcx,[rsp+48]
ctf.exe+31495 - movzx eax,byte ptr [rcx]
; dump rcx -> A4 77 C4 10 D6 5D D5 BD 1F 66 C2 44 DA B6 2E 4A FF 87 84 82 EB FB 9F BB 4F FD CC 05 32 6B 9A C1 89 01 0E 00
ctf.exe+31498 - xor al,[rsi+rdi]
; dump rsi -> 31 32 33 34 35 36 37 38 39 30 71 77 65 72 74 79 75 69 6F 70 61 73 64 66 67 68 6A 6B 6C 7F 00 (my input ptr)
ctf.exe+3149B - mov [rsp+23],al
ctf.exe+3149F - cmp rdx,01 { 1 }
-> not jumped
ctf.exe+34DCA - movzx eax,byte ptr [rcx+01]
ctf.exe+34DCE - xor al,[rsi+rdi+01]
ctf.exe+34DD2 - mov [rsp+24],al
ctf.exe+34DD6 - cmp rdx,02 { 2 }
-> not jumped
ctf.exe+27935 - movzx eax,byte ptr [rcx+02]
ctf.exe+27939 - xor al,[rsi+rdi+02]
ctf.exe+2793D - mov [rsp+25],al
ctf.exe+27941 - cmp rdx,03 { 3 }
ctf.exe+27945 - je ctf.exe+27956
-> 반복 (.. cmp rdx,1c)
ctf.exe+2CE8E - movzx eax,byte ptr [rcx+1C]
ctf.exe+2CE92 - xor al,[rsi+rdi+1C]
ctf.exe+2CE96 - mov [rsp+3F],al
ctf.exe+2CE9A - movdqu xmm0,[rsp+23]
ctf.exe+2CEA0 - movdqu xmm1,[rsp+30]
ctf.exe+2CEA6 - pcmpeqb xmm0,[ctf.exe+17420] { (1803690983) }
ctf.exe+2CEAE - pcmpeqb xmm1,[ctf.exe+17430] { (-813998651) }
ctf.exe+2CEB6 - pand xmm1,xmm0
ctf.exe+2CEBA - pmovmskb eax,xmm1
ctf.exe+2CEBE - cmp eax,0000FFFF { 65535 }
ctf.exe+2CEC3 - sete al
ctf.exe+2CEC6 - mov rdx,[rsp+40]
ctf.exe+2CECB - test rdx,rdx
핵심 검증 루틴까지 왔습니다.
ctf.exe+17420에 있는 값이랑 rcx[i] ^ input[i]랑 비교합니다.
17420

rcx

rcx ^ 17420으로 input을 구할 수 있습니다.
-- ctf.exe+2CE8E: rcx
local key = 0x56D2F0
local n = readBytes(0x140017420, 16, true)
local m = readBytes(0x140017430, 16, true)
local rcx = readBytes(key, 29, true)
local x = {table.unpack(n)}
table.move(m, 4, 16, #x+1, x)
local flag = {}
for i=1,29 do
flag[i] = string.char(x[i] ~ rcx[i]) end
print(table.concat(flag))

플래그를 입력하면 정답입니다!가 출력됩니다.