rev-basic의 마지막 문제다.
늘 하던대로 우선 비교함수식을 찾으려고 디버거에서 문자열검색을 했는데 "I_am_KEY"라는 문자열이 있다. 일단 이런게 있구나라 생각하고 비교함수를 확인해보자.
지금까지와는 뭔가 느낌이 다른게 머리가 아프다. 그래도 대충 큰 것만 확인해보자면, strlen을 호출해서 입력 문자열의 길이를 확인한다. 그리고 실행하면서 확인해본 결과 스택[rsp+40]에는 입력 문자열, 스택[rsp+24]에는 입력 문자열 배열의 크기가 저장된다.
그리고 디버거를 따라가며 확인해보니 문자열 길이가 맞지 않으면 바로 ret으로 넘어가고, 문자열 길이를 맞춰서 가보면 마지막엔 [7FF628904000]과 비교한다.
00007FF628904000 7E 7D 9A 8B 25 2D D5 3D 03 2B 38 98 27 9F 4F BC ~}..%-Õ=.+8.'.O¼
00007FF628904010 2A 79 00 7D C4 2A 4F 58 00 00 00 00 00 00 00 00 *y.}Ä*OX........
이번에는 정신건강에 이로운 IDA로 디컴파일을 해보자
우선 이 sub_140001000비교함수를 디컴파일해봤다. 여기서 v3에 입력된 문자열의 길이를 저장하고 문자열 길이부터 확인한다. (v3+1)%8 == 0이 아니면 추가 비교 없이 "Wrong"을 출력하고 종료된다. 프로그램에 직접적으로 한글자씩 맞추는걸 막은 것 같다.
문자열 길이 확인 후에는 sub_1400010A0함수를 호출한다. 이 함수도 확인해보자.
여기서 아까 위에서 확인했던 "I_am_KEY"문자열을 사용한다.
대충 설명하자면 input[(j + 1) & 7]에 ~~4020[key[j] ^ input[j & 7]]값을 더하고 rotate right를 5만큼 해서 저장한다. 초기값은 input[0]이다.
말로보면 간단한데 이거 역산식짜다가 머리가 터질뻔했다.
def rol(x, n):
shiftBit = x << n
shiftBit &= 255
carryBit = x >> 8 - n
return shiftBit | carryBit
def ror(x, n):
shiftBit = x >> n
carryBit = x << (8 - n)
carryBit &= 255
return shiftBit | carryBit
key = 'I_am_KEY'
enc = '7E 7D 9A 8B 25 2D D5 3D 03 2B 38 98 27 9F 4F BC 2A 79 00 7D C4 2A 4F 58' #7FF628904000
#byte_140004020
tmp = '63 7C 77 7B F2 6B 6F C5 30 01 67 2B FE D7 AB 76 CA 82 C9 7D FA 59 47 F0 AD D4 A2 AF 9C A4 72 C0 B7 FD 93 26 36 3F F7 CC 34 A5 E5 F1 71 D8 31 15 04 C7 23 C3 18 96 05 9A 07 12 80 E2 EB 27 B2 75 09 83 2C 1A 1B 6E 5A A0 52 3B D6 B3 29 E3 2F 84 53 D1 00 ED 20 FC B1 5B 6A CB BE 39 4A 4C 58 CF D0 EF AA FB 43 4D 33 85 45 F9 02 7F 50 3C 9F A8 51 A3 40 8F 92 9D 38 F5 BC B6 DA 21 10 FF F3 D2 CD 0C 13 EC 5F 97 44 17 C4 A7 7E 3D 64 5D 19 73 60 81 4F DC 22 2A 90 88 46 EE B8 14 DE 5E 0B DB E0 32 3A 0A 49 06 24 5C C2 D3 AC 62 91 95 E4 79 E7 C8 37 6D 8D D5 4E A9 6C 56 F4 EA 65 7A AE 08 BA 78 25 2E 1C A6 B4 C6 E8 DD 74 1F 4B BD 8B 8A 70 3E B5 66 48 03 F6 0E 61 35 57 B9 86 C1 1D 9E E1 F8 98 11 69 D9 8E 94 9B 1E 87 E9 CE 55 28 DF 8C A1 89 0D BF E6 42 68 41 99 2D 0F B0 54 BB 16 CF 32 25 34 56 3D FF FF 30 CD DA CB A9 C2 00 00'
enc = enc.split(' ')
tmp = tmp.split(' ')
res = []
chars = []
for i in range(len(enc)):
res.append(int(enc[i], 16))
for i in range(len(tmp)):
chars.append(int(tmp[i], 16))
for k in reversed(range(3)):
for i in range(16):
for j in reversed(range(8)):
res[k * 8 + ((j + 1) & 7)] = (rol(res[k * 8 + ((j + 1) & 7)], 5) - chars[ord(key[j]) ^ res[k * 8 + (j & 7)]]) & 0xFF
flag = ''
for i in range(len(res)):
flag += chr(res[i])
print(flag)
중간에 쓸데없는것 같이 보이는 for문이 많은 이유는 파이썬의 타입에러 때문이다.. 후... c로 하면 더 복잡하니 악으로 깡으로 버틴다.
결론만 말하자면 예전에 풀었던 몇 번이더라.. rev-basic-5였었나... 이 문제와 같이 마지막에서 부터 하나씩 내려오는 식으로 문제를 풀어야한다.
각 인덱스에 k * 8을 더해준 이유는 파이썬에서는 sub_140001000비교함수와 같이 인덱스를 직접적으로 못건들기 때문에 계산식 안에서 처리해줬다.
늙어서 눈이 침침해진건지 계산식을 계속 잘못봐서 이거 왜안되지를 3시간동안 반복하다가 겨우 오류 찾았는데 그 다음엔 key인덱스 잘못잡아서 또 한 30분 헤멨다.. 왜이럴까
여담으로 수식 외에도 이게 인덱스를 계속 왔다갔다 하는거다 보니 out of range error가 계속 발생했다. 그래서 그냥 byte_140004020을 00 00부분까지 싹다 긁어왔더니 그때부턴 에러가 안나오더라
'Security > Reversing' 카테고리의 다른 글
[wargame.kr] DLL with notepad (0) | 2022.07.13 |
---|---|
Secure Mail (0) | 2022.07.13 |
Dreamhack rev-basic-8 (0) | 2022.07.05 |
Dreamhack rev-basic-7 (0) | 2022.06.21 |
Dreamhack rev-basic-6 (0) | 2022.06.01 |