Christmas CTF 2020 - lock
처음에 dump파일이 주어진다.
Hxd나 메모장으로 해당파일을 열어보면 ARM 어셈블리어로 구성된 내용을 확인할 수 있다.
해당 dump파일을 변환하여 ELF파일로 바꿔서 아이다로 편하게 볼 수 있을까? 고민했지만, 실패했다.
정말 오랜만에 어셈블리어를 읽기시작했다. (STR과 LDR의 개념을 잘 익혀두는 것이 좋다.)
0000000000000c50 <main>:
c50: a9be7bfd stp x29, x30, [sp, #-32]! // 스택 공간
c54: 910003fd mov x29, sp
c58: d2800021 mov x1, #0x1 // #1
c5c: d2800260 mov x0, #0x13 // #19
c60: 97fffee0 bl 7e0 <calloc@plt>
c64: f9000be0 str x0, [sp, #16]
c68: 97ffff94 bl ab8 <sub_ab8>
c6c: 97ffff51 bl 9b0 <sub_9b0>
c70: f9000fe0 str x0, [sp, #24] // [sp+24]=return value
c74: 97ffff3e bl 96c <sub_96c> // 그냥 print
c78: f9400be1 ldr x1, [sp, #16]
c7c: 90000000 adrp x0, 0 <_init-0x760>
c80: 9138a000 add x0, x0, #0xe28 // #0xe28 '%s'
c84: 97fffeeb bl 830 <__isoc99_scanf@plt>
c88: f9400fe1 ldr x1, [sp, #24] // x1=fixed_value1
c8c: f9400be0 ldr x0, [sp, #16]
c90: 97ffffa8 bl b30 <sub_b30>
c94: f9400be0 ldr x0, [sp, #16]
c98: 97fffee2 bl 820 <free@plt>
c9c: 52800000 mov w0, #0x0 // #0
ca0: a8c27bfd ldp x29, x30, [sp], #32
ca4: d65f03c0 ret
분석을 진행해보면, <sub_ab8>함수와 <sub_b30>함수가 중요하다.
0000000000000ab8 <sub_ab8>:
ab8: a9be7bfd stp x29, x30, [sp, #-32]!
abc: 910003fd mov x29, sp // x29=[sp]
ac0: 52800103 mov w3, #0x8 // w3=8
ac4: 90000000 adrp x0, value0@page // x0=#value0 (주소)
ac8: 9136e002 add x2, x0, value0@pageoff // x2=[value0]
acc: 528007c1 mov w1, #0x3e // w1=#62
ad0: 90000000 adrp x0, value1@page // x0 =#value1 (주소)
ad4: 91372000 add x0, x0, value1@pageoff // x0 = [value1]
ad8: 97ffffc9 bl 9fc <sub_9fc>
adc: f9000fe0 str x0, [sp, #24]
ae0: f9400fe0 ldr x0, [sp, #24]
ae4: a8c27bfd ldp x29, x30, [sp], #32
ae8: d65f03c0 ret
<sub_ab8>함수는 <sub_9fc>에서 쓰이는 파라미터를 저장하고, 전달하는 내용이라고 인식하면 된다.
00000000000009fc <sub_9fc>:
9fc: a9bc7bfd stp x29, x30, [sp, #-64]!
a00: 910003fd mov x29, sp
a04: f90017e0 str x0, [sp, #40] // [sp+40] = value1
a08: b90027e1 str w1, [sp, #36] // [sp+36] = 62
a0c: f9000fe2 str x2, [sp, #24] // [sp+24] = value0
a10: b90023e3 str w3, [sp, #32] // [sp+32] = 8
a14: b94027e0 ldr w0, [sp, #36] // w0 = [sp+36] #62
a18: 11000400 add w0, w0, #0x1 // w0 = w0+1 #63
a1c: 93407c00 sxtw x0, w0
a20: 97ffff68 bl 7c0 <malloc@plt>
a24: f9001fe0 str x0, [sp, #56] // [sp+56] = malloc size
a28: b98027e0 ldrsw x0, [sp, #36] // x0 = [sp+36] #62
a2c: f9401fe1 ldr x1, [sp, #56] // x1 = malloc size
a30: 8b000020 add x0, x1, x0 // x0=x1+x0
a34: 3900001f strb wzr, [x0] // x0=0
a38: b90037ff str wzr, [sp, #52] // [sp+52]=0
a3c: 14000018 b a9c <sub_9fc+0xa0>
a40: b98037e0 ldrsw x0, [sp, #52] // x0 = [sp+52] #0 -> 1 -> 2 -> 3
a44: f94017e1 ldr x1, [sp, #40] // x1 = [sp+40] #value1
a48: 8b000020 add x0, x1, x0 // x0 = x1 +x0 #value1[i]
a4c: 39400002 ldrb w2, [x0] // w2 = x0 ------ value1 -> w2
=================================================================================================
a50: b94037e0 ldr w0, [sp, #52] // w0 = [sp+52] #0 -> 1 -> 2 -> 3
a54: b94023e1 ldr w1, [sp, #32] // w1 = [sp+32] #8
a58: 1ac10c03 sdiv w3, w0, w1 // w3 = w0/8
a5c: b94023e1 ldr w1, [sp, #32]
a60: 1b017c61 mul w1, w3, w1 // w1 = w3*8
a64: 4b010000 sub w0, w0, w1 // w0 = w0-w1 ##### i%8
a68: 93407c00 sxtw x0, w0 // x0 = w0
a6c: f9400fe1 ldr x1, [sp, #24] // x1 = [sp+24] #value0
a70: 8b000020 add x0, x1, x0 // x0 = x1+x0 #value0[i]
a74: 39400001 ldrb w1, [x0] // w1 = [x0] ----- value0 -> w1
a78: b98037e0 ldrsw x0, [sp, #52] // x0 = [sp+52] #0
a7c: f9401fe3 ldr x3, [sp, #56] // x3 = [sp+56] #mallocsize
a80: 8b000060 add x0, x3, x0 // x0 += x3
a84: 4a010041 eor w1, w2, w1 // w1 = w2^w1
a88: 12001c21 and w1, w1, #0xff
a8c: 39000001 strb w1, [x0] // w1 = [x0]
a90: b94037e0 ldr w0, [sp, #52] // w0 = [sp+52]
a94: 11000400 add w0, w0, #0x1 // w0 = w0 + 1
a98: b90037e0 str w0, [sp, #52] // [sp+52] = w0
a9c: b94037e1 ldr w1, [sp, #52] // w1 = [sp+52]
aa0: b94027e0 ldr w0, [sp, #36] // w0 = [sp+36]
aa4: 6b00003f cmp w1, w0
aa8: 54fffccb b.lt a40 <sub_9fc+0x44> // b.tstop
aac: f9401fe0 ldr x0, [sp, #56]
ab0: a8c47bfd ldp x29, x30, [sp], #64
ab4: d65f03c0 ret
(주석에 대충 어떤식으로 돌아가는지 적어놨다.)
여기까지 내용은 value0와 value1을 xor해서 새로운 value1을 만드는 과정이다.
그 이후에는 main함수에서 <sub_9b0>를 통해 문자열을 복사하고, <sub_96c>를 통해 별의미없는 print를 해주고,
scanf로 입력을 받는다.
마지막으로 <sub_b30>을 확인해보면
0000000000000b30 <sub_b30>:
b30: a9be7bfd stp x29, x30, [sp, #-32]!
b34: 910003fd mov x29, sp
b38: f9000fe0 str x0, [sp, #24] // x0 = key
b3c: f9000be1 str x1, [sp, #16] // x1 = fixed_value1
b40: f9400fe0 ldr x0, [sp, #24]
b44: 91001800 add x0, x0, #0x6
b48: 39400001 ldrb w1, [x0] // w1 = key[6]
b4c: f9400be0 ldr x0, [sp, #16]
b50: 91003800 add x0, x0, #0xe // fixed_value1[e]
b54: 39400000 ldrb w0, [x0]
b58: 6b00003f cmp w1, w0 // key[6] = fixed_value1[0xe]
b5c: 54000761 b.ne c48 <sub_b30+0x118> // b.any
b60: f9400fe0 ldr x0, [sp, #24]
b64: 91001000 add x0, x0, #0x4
b68: 39400001 ldrb w1, [x0] // w1 = key[4]
b6c: f9400be0 ldr x0, [sp, #16]
b70: 91000c00 add x0, x0, #0x3 // fixed_value[3]
b74: 39400000 ldrb w0, [x0]
b78: 6b00003f cmp w1, w0 // key[4] = fixed_value1[0x3]
b7c: 54000661 b.ne c48 <sub_b30+0x118> // b.any
b80: f9400fe0 ldr x0, [sp, #24]
b84: 91000c00 add x0, x0, #0x3
b88: 39400001 ldrb w1, [x0]
b8c: f9400be0 ldr x0, [sp, #16]
b90: 91002800 add x0, x0, #0xa
b94: 39400000 ldrb w0, [x0]
b98: 6b00003f cmp w1, w0 //key[3] = fixed_value1[0xa]
b9c: 54000561 b.ne c48 <sub_b30+0x118> // b.any
ba0: f9400fe0 ldr x0, [sp, #24]
ba4: 91001c00 add x0, x0, #0x7
ba8: 39400001 ldrb w1, [x0]
bac: f9400be0 ldr x0, [sp, #16]
bb0: 91004400 add x0, x0, #0x11
bb4: 39400000 ldrb w0, [x0]
bb8: 6b00003f cmp w1, w0 //key[7] = fixed_value1[0x11]
bbc: 54000461 b.ne c48 <sub_b30+0x118> // b.any
bc0: f9400fe0 ldr x0, [sp, #24]
bc4: 91000400 add x0, x0, #0x1
bc8: 39400001 ldrb w1, [x0]
bcc: f9400be0 ldr x0, [sp, #16]
bd0: 91003800 add x0, x0, #0xe
bd4: 39400000 ldrb w0, [x0]
bd8: 6b00003f cmp w1, w0 //key[1] = fixed_value1[0xe]
bdc: 54000361 b.ne c48 <sub_b30+0x118> // b.any
be0: f9400fe0 ldr x0, [sp, #24]
be4: 91001400 add x0, x0, #0x5 //key[5]
be8: 39400001 ldrb w1, [x0]
bec: f9400be0 ldr x0, [sp, #16]
bf0: 9100d000 add x0, x0, #0x34 //fixed_value1[0x34]
bf4: 39400000 ldrb w0, [x0]
bf8: 6b00003f cmp w1, w0 //key[5]=fixed_value1[0x34]
bfc: 54000261 b.ne c48 <sub_b30+0x118> // b.any
c00: f9400fe0 ldr x0, [sp, #24]
c04: 39400001 ldrb w1, [x0]
c08: f9400be0 ldr x0, [sp, #16]
c0c: 9100d400 add x0, x0, #0x35
c10: 39400000 ldrb w0, [x0]
c14: 6b00003f cmp w1, w0 //key[0]=fixed_value1[0x35]
c18: 54000181 b.ne c48 <sub_b30+0x118> // b.any
c1c: f9400fe0 ldr x0, [sp, #24]
c20: 91000800 add x0, x0, #0x2
c24: 39400001 ldrb w1, [x0]
c28: f9400be0 ldr x0, [sp, #16]
c2c: 91000800 add x0, x0, #0x2
c30: 39400000 ldrb w0, [x0]
c34: 6b00003f cmp w1, w0 //key[2]=fixed_value1[0x2]
c38: 54000081 b.ne c48 <sub_b30+0x118> // b.any
c3c: f9400fe0 ldr x0, [sp, #24]
c40: 97ffffab bl aec <sub_aec>
c44: d503201f nop
c48: a8c27bfd ldp x29, x30, [sp], #32
c4c: d65f03c0 ret
8개의 key문자를 새로운 value1을 통해서 만들고, <sub_aec>로 분기한다.
0000000000000aec <sub_aec>:
aec: a9bd7bfd stp x29, x30, [sp, #-48]!
af0: 910003fd mov x29, sp
af4: f9000fe0 str x0, [sp, #24]
af8: f9400fe0 ldr x0, [sp, #24]
afc: 97ffff29 bl 7a0 <strlen@plt>
b00: 2a0003e3 mov w3, w0 // w3=w0
b04: f9400fe2 ldr x2, [sp, #24] // x2=key
b08: 528003e1 mov w1, #0x1f // #31
b0c: 90000000 adrp x0, value2@page
b10: 91382000 add x0, x0, value2@pageoff // x0=value2
b14: 97ffffba bl 9fc <sub_9fc>
b18: f90017e0 str x0, [sp, #40]
b1c: f94017e0 ldr x0, [sp, #40]
b20: 97ffff3c bl 810 <puts@plt>
b24: d503201f nop
b28: a8c37bfd ldp x29, x30, [sp], #48
b2c: d65f03c0 ret
<sub_aec>는 <sub_ab8>같이 <sub_9fc>를 실행시키기위한 준비 함수처럼 보면된다.
그 후, 또다시 <sub_9fc>가 실행되는데 로직은 같으니 설명은 생략한다.
이런식의 흐름을 파악한 뒤, 문제푸는 코드를 짤 수 있다.
value0 =[0x96, 0x19, 0x7, 0x11, 0x99, 0x19, 0x2, 0x11]
value1 =[0xF7, 0x7B, 0x64, 0x75, 0xFC, 0x7F, 0x65, 0x79, 0xFF, 0x73, 0x6C, 0x7D, 0xF4, 0x77, 0x6D, 0x61, 0xE7, 0x6B, 0x74, 0x65, 0xEC, 0x6F, 0x75, 0x69, 0xEF, 0x63, 0x46, 0x53, 0xDA, 0x5D, 0x47, 0x57, 0xD1, 0x51, 0x4E, 0x5B, 0xD2, 0x55, 0x4F, 0x5F, 0xD9, 0x49, 0x56, 0x43, 0xCA, 0x4D, 0x57, 0x47, 0xC1, 0x41, 0x5E, 0x4B, 0xA9, 0x28, 0x30, 0x22, 0xA2, 0x2C, 0x31, 0x26, 0xA1, 0x20]
value2 = [0x69, 0x22, 0x22, 0x38, 0x1F, 0x43, 0x5B, 0x1C, 0x45, 0xE, 0x3C, 0x8, 0x5, 0x5E, 0x30, 0x17, 0x5F, 0x1B, 0x6, 0x19, 0x3B, 0x44, 0x7, 0x17, 0x6E, 0x7, 0x53, 0x1E, 0x17, 0x55, 0x12]
def sub_9fc(str1, str2 , num1, num2):
for i in range (num2):
str2[i] = str2[i]^str1[i%num1]
return str2
def decode(str1):
flag = ''
for i in str1:
flag+=chr(i)
return flag
fixed_value1 = sub_9fc(value0,value1,8,62)
key = [0 for i in range(8)]
key[6] = fixed_value1[0xe]
key[4] = fixed_value1[0x3]
key[3] = fixed_value1[0xa]
key[7] = fixed_value1[0x11]
key[1] = fixed_value1[0xe]
key[5] = fixed_value1[0x34]
key[0] = fixed_value1[0x35]
key[2] = fixed_value1[0x2]
_key=decode(key)
print(_key)
fixed_value2 = sub_9fc(key,value2,8,31)
flag = decode(fixed_value2)
print(flag)
1ockd0or
XMAS{s4nta_can_enter_the_h0use}