코드 자체는 그냥 연산을 따라가면 확인할 수 있을 것 같은데 처음보는 어셈블리 명령어가 보인다.
00007FF644D41044 | D2C0 | rol al,cl |
여기서 rol이라는 명령어를 알아보기 전에 al과 cl에 대해서 먼저 알아보자면 어셈블리어에서는 범용 레지스터가 있다. 32비트로 E(A, B, C, D)X, 그리고 64비트 R(A, B, C, D)X인데 값을 잠깐 저장하는데 쓰인다. (각 레지스터마다 주된 사용처가 있지만 신경쓸 필요 X)
이 범용 레지스터에서 하위 비트를 부르는 명칭이 있다. 예를 들어 AX는 RAX(EAX)의 하위 4바이트(16비트)이다. 아래의 그림을 참고하자.
출처: https://kuaaan.tistory.com/449
그러면 이제 [ROL AL, CL]이라는 명령어의 의미는 "RAX의 하위 8비트를 RCX의 하위 8비트만큼 ROL해서 AL에 저장해라."라는 의미이다.
ROL명령어는 간단히 말해서 왼쪽으로 비트회전이다. 코딩을 조금이라도 해 본 사람이라면 비트시프트에 대해서 알고 있을 것이다. 기본적으로 왼쪽으로 비트시프트를 하면 보통 최상위 비트는 그대로 사라진다. 그러나 비트회전은 최상위 비트를 CARRY 플래그와 최하위 비트로 복사한다. 비트가 말 그대로 회전한다는 것이다.
최종적으로 [ROL AL, CL]의 의미는 "RAX의 하위 8비트를 RCX의 하위 8비트만큼 왼쪽으로 비트회전해서 AL에 저장해라."라는 뜻이다.
따라서 비교함수식은 (rol(input[i], i & 7)) ^ i == enc[i]
이를 통해 역산식을 구하면 input[i] = ror(enc[i] ^ i, i & 7)이 된다.
디버거를 따라가면서 확인해봤다. input[i] + input[i+1] == str[i]가 되어야한다. 그렇다면 우리가 구해야 할 값은 input이고 str을 알고 있는데 i는 24까지 가며 덤프값을 통해 확인해봤을 때 str[24]는 00이다. input[i] == str[i] - input[i+1]인데 최종 마지막에 들어가는 input[24]를 NULL로 생각하면서 한칸씩 내려오는 식으로 코드를 짜면 된다.
str = 'AD D8 CB CB 9D 97 CB C4 92 A1 D2 D7 D2 D6 A8 A5 DC C7 AD A3 A1 98 4C 00'
str = str.split(' ')
str.reverse()
res = ''
tmp = int(str[0], 16)
for i in range(0, 23): #0x18 == 24
tmp = int(str[i + 1], 16) - tmp
res += chr(tmp)
print(res[::-1])
사실 이번 문제를 4번문제와 동일하게 디컴파일된 함수를 그대로 파이썬 코드에 넣어서 풀었을 때 이상한 문자열이 출력됐었다. 왜냐하면 이번 문제는 문자열 하나 하나를 독립적으로 보는게 아닌 입력된 문자열에서 현재 인덱스와 다음 인덱스를 불러와서 계산을 하는 문제여서 역산이 필요한 문제였기 때문이다. 앞으로는 계산이 좀 더 필요할 것 같다.