Processing math: 100%

바로 비교함수를 확인해보자

코드 자체는 그냥 연산을 따라가면 확인할 수 있을 것 같은데 처음보는 어셈블리 명령어가 보인다.

00007FF644D41044 | D2C0                     | rol al,cl                               |

 여기서 rol이라는 명령어를 알아보기 전에 al과 cl에 대해서 먼저 알아보자면 어셈블리어에서는 범용 레지스터가 있다. 32비트로 EA,B,C,DX, 그리고 64비트 RA,B,C,DX인데 값을 잠깐 저장하는데 쓰인다. X
 
 이 범용 레지스터에서 하위 비트를 부르는 명칭이 있다. 예를 들어 AX는 RAXEAX의 하위 4바이트16이다. 아래의 그림을 참고하자.

출처: https://kuaaan.tistory.com/449

그러면 이제 [ROL  AL, CL]이라는 명령어의 의미는 "RAX의 하위 8비트를 RCX의 하위 8비트만큼 ROL해서 AL에 저장해라."라는 의미이다.
 
이번에는 ROL명령어에 대해서 알아보자. 이 부분에 대해서는 아래의 링크를 통해 공부하였다.
https://m.blog.naver.com/sol9501/70091168321

|정수 연산 ①| 시프트와 회전 명령어 및 응용

|정수 연산 1| 시프트와 회전 명령어 및 응용 목표 : 시프트 연산의 기본적이 사용법과 응용 및 각 연산이 ...

blog.naver.com

ROL명령어는 간단히 말해서 왼쪽으로 비트회전이다. 코딩을 조금이라도 해 본 사람이라면 비트시프트에 대해서 알고 있을 것이다. 기본적으로 왼쪽으로 비트시프트를 하면 보통 최상위 비트는 그대로 사라진다. 그러나 비트회전은 최상위 비트를 CARRY 플래그와 최하위 비트로 복사한다. 비트가 말 그대로 회전한다는 것이다. 
 
최종적으로 [ROL  AL, CL]의 의미는  "RAX의 하위 8비트를 RCX의 하위 8비트만큼 왼쪽으로 비트회전해서 AL에 저장해라."라는 뜻이다.
 
따라서 비교함수식은
rol(input[i], i & 7) ^ i == enc[i]
 
이를 통해 역산식을 구하면
input[i] = rorenc[i] ^ i, i & 7이 된다.
 
ROR코드 및 ROL코드는 아래 링크에서 복사해왔다.
https://hacking-ai.tistory.com/68

어셈블리 ROL, ROR 코드 구현

리버싱 문제를 풀다가 ROL, ROR이 나왔는데, 기드라의 경우 디컴파일 결과가 단지 >>와 같이 쉬프트 연산만 수행하는 방식으로 나오는 문제를 겪었다. 따라서, 이를 해결하기 위해 파이썬으로 ROL, R

hacking-ai.tistory.com

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
enc = '52 DF B3 60 F1 8B 1C B5 57 D1 9F 38 4B 29 D9 26 7F C9 A3 E9 53 18 4F B8 6A CB 87 58 5B 39 1E 00'
enc = tuple(enc.split(' '))
res = ''
for i in range(31):
    res += chr(ror((int(enc[i], 16) ^ i), (i&7)))
print(res)

 

 
새로운 명령어로 지식이 늘었다.

'Security > Reversing' 카테고리의 다른 글

Dreamhack rev-basic-9  0 2022.07.05
Dreamhack rev-basic-8  0 2022.07.05
Dreamhack rev-basic-6  0 2022.06.01
Dreamhack rev-basic-5  0 2022.05.28
Dreamhack rev-basic-4  0 2022.05.25

실행부는 앞의 문제와 동일하므로 생략하고 바로 비교함수를 분석해보았다.

00007FF61F771000 | 48:894C24 08             | mov qword ptr ss:[rsp+8],rcx            |
00007FF61F771005 | 48:83EC 18               | sub rsp,18                              |
00007FF61F771009 | C70424 00000000          | mov dword ptr ss:[rsp],0                |
00007FF61F771010 | EB 08                    | jmp chall6.7FF61F77101A                 |
00007FF61F771012 | 8B0424                   | mov eax,dword ptr ss:[rsp]              |
00007FF61F771015 | FFC0                     | inc eax                                 | i++
00007FF61F771017 | 890424                   | mov dword ptr ss:[rsp],eax              |
00007FF61F77101A | 48:630424                | movsxd rax,dword ptr ss:[rsp]           |
00007FF61F77101E | 48:83F8 12               | cmp rax,12                              | str길이 0x12
00007FF61F771022 | 73 31                    | jae chall6.7FF61F771055                 |
00007FF61F771024 | 48:630424                | movsxd rax,dword ptr ss:[rsp]           | index
00007FF61F771028 | 48:8B4C24 20             | mov rcx,qword ptr ss:[rsp+20]           | str
00007FF61F77102D | 0FB60401                 | movzx eax,byte ptr ds:[rcx+rax]         | str[i]
00007FF61F771031 | 48:8D0D E81F0000         | lea rcx,qword ptr ds:[7FF61F773020]     | 주소 7FF61F773020
00007FF61F771038 | 0FB60401                 | movzx eax,byte ptr ds:[rcx+rax]         | rcx+rax(주소 7FF61F773020+str[i]에 저장된 값)
00007FF61F77103C | 48:630C24                | movsxd rcx,dword ptr ss:[rsp]           | index
00007FF61F771040 | 48:8D15 B91F0000         | lea rdx,qword ptr ds:[7FF61F773000]     |
00007FF61F771047 | 0FB60C0A                 | movzx ecx,byte ptr ds:[rdx+rcx]         | rdx[i]
00007FF61F77104B | 3BC1                     | cmp eax,ecx                             | eax와 ecx의 값 비교
00007FF61F77104D | 74 04                    | je chall6.7FF61F771053                  |
00007FF61F77104F | 33C0                     | xor eax,eax                             |
00007FF61F771051 | EB 07                    | jmp chall6.7FF61F77105A                 |
00007FF61F771053 | EB BD                    | jmp chall6.7FF61F771012                 |
00007FF61F771055 | B8 01000000              | mov eax,1                               |
00007FF61F77105A | 48:83C4 18               | add rsp,18                              |
00007FF61F77105E | C3                       | ret                                     |

주석을 달아놓긴 했는데 정확히 어떤 의미냐면

3020덤프

주소 00007FF61F773020을 기준으로 덤프를 캡쳐해온 것이다. 이 주소에서 내가 입력한 문자열 str[i]를 더했을 때

00007FF61F773000  00 4D 51 50 EF FB C3 CF 92 45 4D CF F5 04 40 50  .MQPïûÃÏ.EMÏõ.@P

이 00007FF61F773000주소에 있는 헥스코드 값과 일치해야 된다는 것이다.
맛보기로 수작업으로 했을 때 첫 글자는 ~~~3020주소에서 str[i]를 더해서 00이 나와야 되므로 위 3020덤프에서 헥스값이 00인 주소는 

~~~3072다. 첫 문자는 0x3072-0x3020 = 0x52 따라서 R이다. 첫 문자 R로 입력해서 디버거를 돌렸을 때 다음 루프를 들어가는 것을 확인하여 이가 맞음을 확인했다.
 
이렇게 되면 덤프 밑의 값까지 전부 확인해야되므로 코드를 짤때 어쩔 수 없이 전부 가져가야겠다. 아스키코드의 마지막 값은 7F이므로 ~~~309F까지 저장해서 풀었다.

dump = '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'
dump = tuple(dump.split(' '))
str = '00 4D 51 50 EF FB C3 CF 92 45 4D CF F5 04 40 50 43 63'
str = tuple(str.split(' '))
res = ''
for i in range(18):
    res += chr(dump.index(str[i]))
print(res)

이번에는 디컴파일 없이 어셈블리어를 직접 하나하나 분석했다. 눈은 아픈데 굉장히 뿌듯하다. 
 
시험기간인데 시험공부는 안하고 워게임이나 하고있다.

'Security > Reversing' 카테고리의 다른 글

Dreamhack rev-basic-8  0 2022.07.05
Dreamhack rev-basic-7  0 2022.06.21
Dreamhack rev-basic-5  0 2022.05.28
Dreamhack rev-basic-4  0 2022.05.25
Dreamhack rev-basic-3  0 2022.05.24

+ Recent posts