constWORLDant

처음 만들어 본 64비트 크랙미 분석 본문

0x02 Reverse Engineer/0x03. Etc

처음 만들어 본 64비트 크랙미 분석

data type ConS_tanT 2017.11.30 00:32

64비트 공부하려고 직접 문제 만들어서 x64dbg만을 이용해서 분석해보았습니다.

완벽하게 저를 위한 풀이라.. 이해 안되는 부분 있으면 말씀해주세요 ㅠㅠ 

캡쳐가 너무 하기 귀찮아서 대부분 표에 루틴을 놓아둘겁니다.


헤헤 되게 쉬운 문제지만 초보분들을 위해 파일도 첨부 해둘게요. ^^

(메모장도 같이 드릴게욧 - 티스토리에 넣으니 되게 지저분하네요)

풀이.txt


crackMe_c0nstant.zip



64비트와 32비트는 메인부터 차이가 나는것을 발견했습니다.

아는 동생에게 자문을 조금 구해보니 64비트는 레지스터를 이용하여 값을 가져온다고 합니다. 


64비트를 처음 접해보아서 qword 부분도 살짝 캡쳐 해보았습니다 ^^

 

우리는 이제 4바이트만 들여다봐야하는 것이 아니라, 8바이트까지 들여다 봐야해요

오우.... 눈이 더 아프겠네요 


여담은 여기 까지 하고 본격적으로 분석 시작해보겠습니다 !


(아까 전에 메모장에 적으면서 한 것을 그대로 옮길거라 이제 ~한다. 라고 적혀있습니다 ㅎㅎ) - 서브라임 쓰기 귀찮음 2시간30분잤어요 ㅠㅠ 


00007FF69D4016C2  | 48 8B 05 3F 29 00 0 | mov rax,qword ptr ds:[7FF69D404008]  | rax:&"ALLUSERSPROFILE=C:\\ProgramData"

00007FF69D4016C9  | 48 33 C4            | xor rax,rsp                          |

00007FF69D4016CC  | 48 89 84 24 98 00 0 | mov qword ptr ss:[rsp+98],rax        |

00007FF69D4016D4  | 48 8D 84 24 80 00 0 | lea rax,qword ptr ss:[rsp+80]        | 요상한 값이 rcx에 들어가게 됩니다

00007FF69D4016DC  | 48 8D 0D 75 1B 00 0 | lea rcx,qword ptr ds:[7FF69D403258]  | 7FF69D403258:"~bcyUcyUde~UkUlfkm!"

00007FF69D4016E3  | 48 8B F8            | mov rdi,rax                          | 아직까지는 ~bcy???????? 이 값이 무엇인지 모를것이다


00007FF69D4016E9  | B9 14 00 00 00      | mov ecx,14                           |

00007FF69D4016EE  | F3 A4               | rep movsb byte ptr ds:[rdi],byte ptr |

00007FF69D4016F0  | 48 8D 44 24 60      | lea rax,qword ptr ss:[rsp+60]        | 여기도 이상한 값이 들어가 있다

00007FF69D4016F5  | 48 8D 0D 74 1B 00 0 | lea rcx,qword ptr ds:[7FF69D403270]  | 7FF69D403270:"_NUXALBXOGIGSF]DXFYGZX*+\\PT"

00007FF69D4016FC  | 48 8B F8            | mov rdi,rax                          |

00007FF69D4016FF  | 48 8B F1            | mov rsi,rcx                          |

지금 0x00007FF69D403258 주소에 "~bcyUcyUde~UkUlfkm!" 이 값이 들어가있다고 볼 수 있다.


주소 0x7FF69D403270 주소에는 "_NUXALBXOGIGSF]DXFYGZX*+\\PT" 이 값이 들어있다.


00007FF69D40172E | 48 FF 44 24 28          | inc qword ptr ss:[rsp+28]                      |

00007FF69D401733 | 48 8B 44 24 40          | mov rax,qword ptr ss:[rsp+40]                  | [rsp+40]:"abcdefghijklmnopqrstuvwxyz!"

00007FF69D401738 | 48 8B 4C 24 28          | mov rcx,qword ptr ss:[rsp+28]                  |

00007FF69D40173D | 80 3C 08 00             | cmp byte ptr ds:[rax+rcx],0                    | rax+rcx*1:"bcdefghijklmnopqrstuvwxyz!"

00007FF69D401741 | 75 EB                   | jne crackme_c0nstant.7FF69D40172E              |

또다른 주소 0x7FF69D404038에는 "abcdefghijklmnopqrstuvwxyz!" 해당 값이 존재한다.

a~!까지 0과 비교 하게 된다. 왜 0과 비교를 하느냐. 

배열의 인덱스를 다 검사하게 되면 마지막에 '널 값'이 남기 때문이다.


이제 원리를 아니까 jne 다음 instruction에서 break point를 걸어 복호화 시켜버리자.


해당 루틴이 지나고 나면 "동적할당"을 진행한다.


잠시 메모리 덤프 백업하고 갑시다~~

[핵심 메모리 덤프 추출]

00007FF69D403250   25 73 00 00 25 64 00 00 7E 62 63 79 55 63 79 55    %s..%d..~bcyUcyU   

00007FF69D403260   64 65 7E 55 6B 55 6C 66 6B 6D 21 00 25 64 00 00    de~UkUlfkm!.%d..   

00007FF69D403270   5F 4E 55 58 41 4C 42 58 4F 47 49 47 53 46 5D 44    _NUXALBXOGIGSF]D   

00007FF69D403280   58 46 59 47 5A 58 2A 2B 5C 50 54 00 00 00 00 00    XFYGZX*+\PT.....   


00007FF69D404038   61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70    abcdefghijklmnop   

00007FF69D404048   71 72 73 74 75 76 77 78 79 7A 21 00 00 00 00 00    qrstuvwxyz!.....   

00007FF69D404058   76 7C 71 77 6B 49 7F 65 4F 78 24 66 75 4F 43 27    v|qwkI.eOx$fuOC'   

00007FF69D404068   65 74 21 75 74 4F 74 79 21 79 77 23 7E 64 21 69    et!utOty!yw#~d!i   

00007FF69D404078   4F 76 7F 62 4F 42 75 66 23 62 63 79 7E 77 7D 00    Ov.bOBuf#bcy~w}.   



그럼 여기서 우리는 복원코드를 만들 수 있다. 우선 길이는 신경쓰지 않기로 한다.

char *one = "~bcyUcyUde~UkUlfkm!";

char *two = "_NUXALBXOGIGSF]DXFYGZX*+\\PT";

char *three = "abcdefghijklmnopqrstuvwxyz!"; 라고 가정하자. 


아까전에 복원 한 char *three에 내가 입력한 문자열을 덮어 씌운다.

00007FF69D40117E  | 4C 8B 4C 24 28      | mov r9,qword ptr ss:[rsp+28]          | [rsp+28]:&"abcdefghijklmnopqrstuvwxyz!"

00007FF69D401183  | 45 33 C0            | xor r8d,r8d                           |

00007FF69D401186  | 48 8B 54 24 50      | mov rdx,qword ptr ss:[rsp+50]         | [rsp+50]:"%s"

00007FF69D40118B  | 48 8B C8            | mov rcx,rax                           |

00007FF69D40118E  | E8 5D FF FF FF      | call crackme_c0nstant.7FF69D4010F0    | 문자열을 입력한다


그럼, 이제 *three의 명칭을 *input_val로 바꾸어 두겠다.


call crackme_c0nstant.7FF69D4010F0 여기에서 step in 해서 살펴보게 되면 scanf 함수가 존재한다.

그로인하여 확실히 문자열을 입력받는 구간임이 증명되었다.


내가 만든 문제이지만, 현재는 몇자리인지 모른다는 가정하에 진행해보겠다. 


우선 별다른 루틴없이 다음 버퍼가 등장한다.

이번엔 %d를 입력하라고 한다. 

문자열을 입력했으니 이번엔 문자열의 갯수를 입력한다.

이렇게 짜본 이유는 입력 값 검증을 조금 특이하게 해보고 싶었다.


문자열 10개 입력했으니, 문자열 갯수도 10으로 입력한다.




아참, x64dbg는 루틴을 굳이 들어가지 않아도 마우스 커서를 통해 들여다 볼 수 있는 기능도 가지고 있다.


지금 보면 이러한 instruction이 존재한다.

00007FF69D401A30  | 48 3B 0D D1 25 00 0 | cmp rcx,qword ptr ds:[7FF69D404008]   |


[7FF69D404008] 내부 값 49 F2 5E 85 

rcx 의 값 0x1D 98 49 F2 5E 85

QWORD만큼 비교해보면 '49 F2 5E 85'로 일치한다. 


그 다음 주소 jne crackme_c0nstant.7FF69D401A4C에 관여하지 않는다


그렇다면 자연스레 rip는 0x7FF69D401A3A로 가게 된다.


다음 만나는 instruction은 rol rcx, 10이다

rol이란, 왼쪽으로 시프트 하되 '순환'된다.


rol 명령을 수행하기 전 rcx는  00001D9849F25E85 

rol 명령을 수행한 후 rcx는   1D9849F25E85000


여담: rol 처음 보는 명령어라서 종이에 적어보다 2시간 30분 잠들어버렸다 ㅋㅋㅋ

갈수록 글씨가 엉망이 됨을 볼 수 있다 ^^;;




다시 다시 문제로 돌아와서 핵심 루틴을 설명하겠다.

메모장에 이쁘게 화살표까지 그렸는데.. 다 깨진다..


 00007FF69D40162D  | 83 7C 24 28 1B      | cmp dword ptr ss:[rsp+28],1B         | 내가 입력한 10자리와 1B를 비교

00007FF69D401632  | 75 38               | jne crackme_c0nstant.7FF69D40166C    | 지금 누가 봐도 같지 않으니 분기   --------------

00007FF69D401634  | 48 8B 44 24 20      | mov rax,qword ptr ss:[rsp+20]        | [rsp+20]:"aaaaaaaaaa"       |

00007FF69D401639  | 48 89 44 24 08      | mov qword ptr ss:[rsp+8],rax         | [rsp+8]:"aaaaaaaaaa"        |

00007FF69D40163E  | 48 C7 04 24 FF FF F | mov qword ptr ss:[rsp],FFFFFFFFFFFFF |                             |

00007FF69D401646  | 48 FF 04 24         | inc qword ptr ss:[rsp]               |

00007FF69D40164A  | 48 8B 44 24 08      | mov rax,qword ptr ss:[rsp+8]         | [rsp+8]:"aaaaaaaaaa"        |

00007FF69D40164F  | 48 8B 0C 24         | mov rcx,qword ptr ss:[rsp]           |

00007FF69D401653  | 80 3C 08 00         | cmp byte ptr ds:[rax+rcx],0          |                             |

00007FF69D401657  | 75 ED               | jne crackme_c0nstant.7FF69D401646    |

00007FF69D401659  | 48 8B 04 24         | mov rax,qword ptr ss:[rsp]           |

00007FF69D40165D  | 48 83 F8 1B         | cmp rax,1B                           | rax:"aaaaaaaaaa"            |

00007FF69D401661  | 75 09               | jne crackme_c0nstant.7FF69D40166C    |

00007FF69D401663  | B8 01 00 00 00      | mov eax,1                            |

00007FF69D401668  | EB 07               | jmp crackme_c0nstant.7FF69D401671    |                                       

00007FF69D40166A  | EB 05               | jmp crackme_c0nstant.7FF69D401671                                                       |

00007FF69D40166C  | B8 FF FF FF FF      | mov eax,FFFFFFFF                     |        <-    -   -   -  -   -

00007FF69D401671  | 48 83 C4 18         | add rsp,18                           |

00007FF69D401675  | C3                  | ret                                  |


만약에, 입력한 갯수가 1B와 같았다면, mov eax,1 명령을 수행한 후 ret 하면서 스택을 정리하게 될 것이다.

 

올바르지 않은 값을 입력한 상태이기 때문에 mov eax,FFFFFFFF를 만났고 스택을 빠져나가 반환되는 주소는 0x00007FF69D401799이다.

이 주소에서 cmp eax,1 라는 명령을 수행하게 되며, 현재 eax 값이 FFFFFFFF이기 때문에 jne 명령에 만족하여 0x00007FF69D4017E0으로 분기하게 된다.

해당 주소로 분기하게 되면 복호화가 되어 있지 않은 메시지박스가 출력되게 된다.


00007FF69D401794  | E8 87 FE FF FF      | call crackme_c0nstant.7FF69D401620   | 문자열 갯수 체크

00007FF69D401799  | 83 F8 01            | cmp eax,1                            |

00007FF69D40179C  | 75 42               | jne crackme_c0nstant.7FF69D4017E0    | ------------------------------------------------

00007FF69D40179E  | 48 8D 0D EB 1A 00 0 | lea rcx,qword ptr ds:[7FF69D403290]  | 7FF69D403290:"Correct!\n"                       |

00007FF69D4017A5  | E8 C6 F8 FF FF      | call crackme_c0nstant.7FF69D401070   |

00007FF69D4017AA  | 48 8D 8C 24 80 00 0 | lea rcx,qword ptr ss:[rsp+80]        |                                                 |

00007FF69D4017B2  | E8 D9 FD FF FF      | call crackme_c0nstant.7FF69D401590   |

00007FF69D4017B7  | 48 8D 0D E2 1A 00 0 | lea rcx,qword ptr ds:[7FF69D4032A0]  | 7FF69D4032A0:"you press under score >> "        |

00007FF69D4017BE  | E8 AD F8 FF FF      | call crackme_c0nstant.7FF69D401070   |

00007FF69D4017C3  | 48 8D 4C 24 60      | lea rcx,qword ptr ss:[rsp+60]        |                                                 |

00007FF69D4017C8  | E8 F3 F9 FF FF      | call crackme_c0nstant.7FF69D4011C0   |

00007FF69D4017CD  | 48 8D 54 24 5C      | lea rdx,qword ptr ss:[rsp+5C]        |

00007FF69D4017D2  | 48 8D 0D 93 1A 00 0 | lea rcx,qword ptr ds:[7FF69D40326C]  | 7FF69D40326C:"%d"                               |

00007FF69D4017D9  | E8 62 F9 FF FF      | call crackme_c0nstant.7FF69D401140   |

00007FF69D4017DE  | EB 24               | jmp crackme_c0nstant.7FF69D401804    |

00007FF69D4017E0  | 45 33 C9            | xor r9d,r9d                          | < - - - - - - - - - - - - - - - - - - - - - - - -

00007FF69D4017E3  | 4C 8D 05 D6 1A 00 0 | lea r8,qword ptr ds:[7FF69D4032C0]   | 7FF69D4032C0:"good job!"

00007FF69D4017EA  | 48 8D 15 67 28 00 0 | lea rdx,qword ptr ds:[7FF69D404058]  |

00007FF69D4017F1  | 33 C9               | xor ecx,ecx                          |

00007FF69D4017F3  | FF 15 87 18 00 00   | call qword ptr ds:[<&MessageBoxA>]   |

 






그렇다면, 올바르게 1B와 같았다면 jne crackme_c0nstant.7FF69D4017E0 바로 밑의 instruction으로 분기되게 되면서 언더 스코어의 갯수를 입력하라고 할 것이다.


재시작해보자.


27개 : aaaaaaaaaaaaaaaaaaaaaaaaaaa







00007FF69D40162D  | 83 7C 24 28 1B      | cmp dword ptr ss:[rsp+28],1B         | 내가 입력한 10자리와 1B를 비교

00007FF69D401632  | 75 38               | jne crackme_c0nstant.7FF69D40166C    | 같지 않으니 분기

00007FF69D401634  | 48 8B 44 24 20      | mov rax,qword ptr ss:[rsp+20]        | [rsp+20]:"aaaaaaaaaaaaaaaaaaaaaaaaaaa"

00007FF69D401639  | 48 89 44 24 08      | mov qword ptr ss:[rsp+8],rax         | [rsp+8]:"aaaaaaaaaaaaaaaaaaaaaaaaaaa"

00007FF69D40163E  | 48 C7 04 24 FF FF F | mov qword ptr ss:[rsp],FFFFFFFFFFFFF |

00007FF69D401646  | 48 FF 04 24         | inc qword ptr ss:[rsp]               |

00007FF69D40164A  | 48 8B 44 24 08      | mov rax,qword ptr ss:[rsp+8]         | [rsp+8]:"aaaaaaaaaaaaaaaaaaaaaaaaaaa"

00007FF69D40164F  | 48 8B 0C 24         | mov rcx,qword ptr ss:[rsp]           |

00007FF69D401653  | 80 3C 08 00         | cmp byte ptr ds:[rax+rcx],0          | 한 바이트 씩 증가하다가 널이 되는 부분에서 분기하라

00007FF69D401657  | 75 ED               | jne crackme_c0nstant.7FF69D401646    | [rax+rcx]가 여전히 0이 아니면 다시 루틴 돌아라

00007FF69D401659  | 48 8B 04 24         | mov rax,qword ptr ss:[rsp]           | 모든 바이트를 훑고 널이 되었을 때 rax값을 0x1B와 비교해라.

00007FF69D40165D  | 48 83 F8 1B         | cmp rax,1B                           | rax:"aaaaaaaaaaaaaaaaaaaaaaaaaaa"

00007FF69D401661  | 75 09               | jne crackme_c0nstant.7FF69D40166C    | rax가 1B가 맞으면 아래 명령을 수행하라

00007FF69D401663  | B8 01 00 00 00      | mov eax,1                            | 즉, EAX는 1이 나오게 되면서

00007FF69D401668  | EB 07               | jmp crackme_c0nstant.7FF69D401671    |

......

00007FF69D401671  | 48 83 C4 18         | add rsp,18                           | 주소 7FF69D401671로 올바르게 분기하게 된다

00007FF69D401675  | C3                  | ret                                  | 스택 정리


eax는 1이 성립하기 때문에 다음 루틴에 순조롭게 이동할 수 있다.


루틴을 돌다보면 아까전에 char *two라고 선언을 해두었던 변수를 또 한번 만나게 된다. 



배열 혹은 포인터변수가 있을 때는 반복문이 있게 된다. 이 역시 포인터 변수이기 때문에 한 바이트씩 비교해 나가면서 널의 위치를 찾게 된다.

00007FF69D4011D0  | EB 08               | jmp crackme_c0nstant.7FF69D4011DA    |

00007FF69D4011D2  | 8B 04 24            | mov eax,dword ptr ss:[rsp]           |

00007FF69D4011D5  | FF C0               | inc eax                              |

00007FF69D4011D7  | 89 04 24            | mov dword ptr ss:[rsp],eax           |

00007FF69D4011DA  | 48 63 04 24         | movsxd rax,dword ptr ss:[rsp]        |

00007FF69D4011DE  | 48 8B 4C 24 30      | mov rcx,qword ptr ss:[rsp+30]        | [rsp+30]:"_NUXALBXOGIGSF]DXFYGZX*+\\PT"

00007FF69D4011E3  | 48 89 4C 24 10      | mov qword ptr ss:[rsp+10],rcx        | [rsp+10]:"_NUXALBXOGIGSF]DXFYGZX*+\\PT"

00007FF69D4011E8  | 48 C7 44 24 08 FF F | mov qword ptr ss:[rsp+8],FFFFFFFFFFF |

00007FF69D4011F1  | 48 FF 44 24 08      | inc qword ptr ss:[rsp+8]             | < --------------------------------------------

00007FF69D4011F6  | 48 8B 4C 24 10      | mov rcx,qword ptr ss:[rsp+10]        | [rsp+10]:"_NUXALBXOGIGSF]DXFYGZX*+\\PT"      |

00007FF69D4011FB  | 48 8B 54 24 08      | mov rdx,qword ptr ss:[rsp+8]         |                                              |

00007FF69D401200  | 80 3C 11 00         | cmp byte ptr ds:[rcx+rdx],0          | [rcx+rdx]가 널인가?                             | 

00007FF69D401204  | 75 EB               | jne crackme_c0nstant.7FF69D4011F1    | 널이 아니라면 다시 7FF69D4011F1로 분기하여라 ------- --

00007FF69D401206  | 48 8B 4C 24 08      | mov rcx,qword ptr ss:[rsp+8]         |

00007FF69D40120B  | 48 FF C9            | dec rcx                              | rcx:"_NUXALBXOGIGSF]DXFYGZX*+\\PT"

00007FF69D40120E  | 48 3B C1            | cmp rax,rcx                          | rcx:"_NUXALBXOGIGSF]DXFYGZX*+\\PT"

00007FF69D401211  | 73 34               | jae crackme_c0nstant.7FF69D401247    | 


00007FF69D401213  | 48 63 04 24         | movsxd rax,dword ptr ss:[rsp]        |

00007FF69D401217  | 48 8B 4C 24 30      | mov rcx,qword ptr ss:[rsp+30]        | [rsp+30]:"_NUXALBXOGIGSF]DXFYGZX*+\\PT"

00007FF69D40121C  | 0F BE 04 01         | movsx eax,byte ptr ds:[rcx+rax]      | [rcx+rax]값을 부호 확장하여 eax에 대입 현재 = '_'가 된다 

00007FF69D401220  | 83 F8 58            | cmp eax,58                           | 58:'X'

00007FF69D401223  | 75 1E               | jne crackme_c0nstant.7FF69D401243    | X와 '_'는 다르기 때문에 7FF69D401243으로 분기한다.

00007FF69D401225  | 48 63 04 24         | movsxd rax,dword ptr ss:[rsp]        |

00007FF69D401229  | 48 8B 4C 24 30      | mov rcx,qword ptr ss:[rsp+30]        |

00007FF69D40122E  | 0F BE 04 01         | movsx eax,byte ptr ds:[rcx+rax]      |

00007FF69D401232  | 83 F0 07            | xor eax,7                            |

......

00007FF69D401243  | EB 8D               | jmp crackme_c0nstant.7FF69D4011D2    | 그 다음 또 진행하게 된다. 




......

00007FF69D401213  | 48 63 04 24         | movsxd rax,dword ptr ss:[rsp]        |

00007FF69D401217  | 48 8B 4C 24 30      | mov rcx,qword ptr ss:[rsp+30]        | [rsp+30]:"_NUXALBXOGIGSF]DXFYGZX*+\\PT"

00007FF69D40121C  | 0F BE 04 01         | movsx eax,byte ptr ds:[rcx+rax]      | [rcx+rax]값을 부호 확장하여 eax에 대입 현재 = '_'가 된다 

00007FF69D401220  | 83 F8 58            | cmp eax,58                           | 58:'X'

00007FF69D401223  | 75 1E               | jne crackme_c0nstant.7FF69D401243    | X와 '_'는 다르기 때문에 7FF69D401243으로 분기한다.

......

00007FF69D401243  | EB 8D               | jmp crackme_c0nstant.7FF69D4011D2    | 그 다음 또 진행하게 된다.


그렇다면, 만약 EAX가 'X'가 맞았더라면? (inc 명령이 있기 때문에 한 바이트 한 바이트 계속 비교 할 수 있는 기회가 존재) 


00007FF69D401220  | 83 F8 58            | cmp eax,58                           | 58:'X'

00007FF69D401223  | 75 1E               | jne crackme_c0nstant.7FF69D401243    |

00007FF69D401225  | 48 63 04 24         | movsxd rax,dword ptr ss:[rsp]        | eax가 'X'가 맞았다면 여기로 분기하게 된다

00007FF69D401229  | 48 8B 4C 24 30      | mov rcx,qword ptr ss:[rsp+30]        | [rsp+30]:"_NUXALBXOGIGSF]DXFYGZX*+\\PT"

00007FF69D40122E  | 0F BE 04 01         | movsx eax,byte ptr ds:[rcx+rax]      |

00007FF69D401232  | 83 F0 07            | xor eax,7                            | eax ^= 0x7 하게 되면 "_"가 나온다.


그럼, 센스있게 X가 총 몇개 인지도 보면 좋을거다. 이건 분석을 조금이나마 많이 해봐야 보이지 않을까 싶다.

지금 전체 문장이 "_NUXALBXOGIGSF]DXFYGZX*+\\PT" 인데, 'X'가 3,7,16,21첨자에 존재한다. 

그렇다면, under score의 갯수는 4가 된다. 맨 앞의 _는 '기존에' 있는 값이기 때문에 신경 쓰지 않았다. 


그럼 우리는 이러한 조건을 알아내었으니 재시작 하되, "조건 : 27자리 이되, [3],[7],[16],[21]에서 0x5F("_")가 나오게 설정하라 " 를 만족해보자.

aa_aaa_aaaaaaaa_aaaa_aaaaaa 


언더스코어는 4개가 확실해졌다.



이렇게 입력 한 후 루틴을 돌아보니 this_is_not_a_flag! 라는 문구가 뜨게 되었다.

_NUXALBXOGIGSF]DXFYGZX*+\\PT 이 문자열과 _의 인덱스 조건이 성립하지 않는다.

그렇다면 어디선가 놓친 부분이 있을거라 판단했다.

bp를 걸어 둔 부분에서 실수를 하였다. 다시 27자리를 입력하고 진행해보았다.

내가 만든 문제이지만, 트레이싱을 하면서 하니 이런 실수를 했다 ㅠㅠ 자괴감....?! 괜찮다 멘탈은 강하다 ㅋㅋㅋㅋ


Correct !!가 출력되고 난 뒤 char *one 선언된 부분을 발견하게 되었다.

00007FF69D40179E  | 48 8D 0D EB 1A 00 0 | lea rcx,qword ptr ds:[7FF69D403290]  | rcx:"Correct!\n", 7FF69D403290:"Correct!\n"

00007FF69D4017A5  | E8 C6 F8 FF FF      | call crackme_c0nstant.7FF69D401070   | 여기 진입해서 알아볼 것이 있다 

00007FF69D4017AA  | 48 8D 8C 24 80 00 0 | lea rcx,qword ptr ss:[rsp+80]        |

00007FF69D4017B2  | E8 D9 FD FF FF      | call crackme_c0nstant.7FF69D401590   |

00007FF69D4017B7  | 48 8D 0D E2 1A 00 0 | lea rcx,qword ptr ds:[7FF69D4032A0]  | rcx:"Correct!\n", 7FF69D4032A0:"you press under score >> "

00007FF69D4017BE  | E8 AD F8 FF FF      | call crackme_c0nstant.7FF69D401070   |

00007FF69D4017C3  | 48 8D 4C 24 60      | lea rcx,qword ptr ss:[rsp+60]        |

00007FF69D4017C8  | E8 F3 F9 FF FF      | call crackme_c0nstant.7FF69D4011C0   |

00007FF69D4017CD  | 48 8D 54 24 5C      | lea rdx,qword ptr ss:[rsp+5C]        |

00007FF69D4017D2  | 48 8D 0D 93 1A 00 0 | lea rcx,qword ptr ds:[7FF69D40326C]  | rcx:"Correct!\n", 7FF69D40326C:"%d"

00007FF69D4017D9  | E8 62 F9 FF FF      | call crackme_c0nstant.7FF69D401140   |

00007FF69D4017DE  | EB 24               | jmp crackme_c0nstant.7FF69D401804    |

00007FF69D4017E0  | 45 33 C9            | xor r9d,r9d                          |

00007FF69D4017E3  | 4C 8D 05 D6 1A 00 0 | lea r8,qword ptr ds:[7FF69D4032C0]   | 7FF69D4032C0:"good job!" 


진입해서 알아보니 Correct! 출력하는 부분이었다.


00007FF69D40179C  | 75 42               | jne crackme_c0nstant.7FF69D4017E0    |

00007FF69D40179E  | 48 8D 0D EB 1A 00 0 | lea rcx,qword ptr ds:[7FF69D403290]  | 7FF69D403290:"Correct!\n"

00007FF69D4017A5  | E8 C6 F8 FF FF      | call crackme_c0nstant.7FF69D401070   | 여기 진입해서 알아볼 것이 있다

00007FF69D4017AA  | 48 8D 8C 24 80 00 0 | lea rcx,qword ptr ss:[rsp+80]        |

00007FF69D4017B2  | E8 D9 FD FF FF      | call crackme_c0nstant.7FF69D401590   | 여기가 진짜배기다

00007FF69D4017B7  | 48 8D 0D E2 1A 00 0 | lea rcx,qword ptr ds:[7FF69D4032A0]  | 7FF69D4032A0:"you press under score >> "

00007FF69D4017BE  | E8 AD F8 FF FF      | call crackme_c0nstant.7FF69D401070   |

00007FF69D4017C3  | 48 8D 4C 24 60      | lea rcx,qword ptr ss:[rsp+60]        |

00007FF69D4017C8  | E8 F3 F9 FF FF      | call crackme_c0nstant.7FF69D4011C0   |

00007FF69D4017CD  | 48 8D 54 24 5C      | lea rdx,qword ptr ss:[rsp+5C]        |

00007FF69D4017D2  | 48 8D 0D 93 1A 00 0 | lea rcx,qword ptr ds:[7FF69D40326C]  | 7FF69D40326C:"%d"

00007FF69D4017D9  | E8 62 F9 FF FF      | call crackme_c0nstant.7FF69D401140   |

00007FF69D4017DE  | EB 24               | jmp crackme_c0nstant.7FF69D401804    |

00007FF69D4017E0  | 45 33 C9            | xor r9d,r9d                          |

00007FF69D4017E3  | 4C 8D 05 D6 1A 00 0 | lea r8,qword ptr ds:[7FF69D4032C0]   | 7FF69D4032C0:"good job!" 








주소 0x7FF69D41590에 들어가기 전 



0x7FF69D401590에 들어가게 되면, char *one이 선언된 부분이 나오고 여기서 바로 알아차릴 수 있는것은 xor eax,A이다.

00007FF69D401590  | 48 89 4C 24 08      | mov qword ptr ss:[rsp+8],rcx         | [rsp+8]:"Correct!\n"

00007FF69D401595  | 48 83 EC 48         | sub rsp,48                           |

00007FF69D401599  | C7 44 24 20 00 00 0 | mov dword ptr ss:[rsp+20],0          |

00007FF69D4015A1  | EB 0A               | jmp crackme_c0nstant.7FF69D4015AD    |

00007FF69D4015A3  | 8B 44 24 20         | mov eax,dword ptr ss:[rsp+20]        |

00007FF69D4015A7  | FF C0               | inc eax                              |

00007FF69D4015A9  | 89 44 24 20         | mov dword ptr ss:[rsp+20],eax        |

00007FF69D4015AD  | 48 63 44 24 20      | movsxd rax,dword ptr ss:[rsp+20]     |

00007FF69D4015B2  | 48 8B 4C 24 50      | mov rcx,qword ptr ss:[rsp+50]        |

00007FF69D4015B7  | 48 89 4C 24 30      | mov qword ptr ss:[rsp+30],rcx        |

00007FF69D4015BC  | 48 C7 44 24 28 FF F | mov qword ptr ss:[rsp+28],FFFFFFFFFF |

00007FF69D4015C5  | 48 FF 44 24 28      | inc qword ptr ss:[rsp+28]            |

00007FF69D4015CA  | 48 8B 4C 24 30      | mov rcx,qword ptr ss:[rsp+30]        |

00007FF69D4015CF  | 48 8B 54 24 28      | mov rdx,qword ptr ss:[rsp+28]        |

00007FF69D4015D4  | 80 3C 11 00         | cmp byte ptr ds:[rcx+rdx],0          | rcx+rdx*1:"~bcyUcyUde~UkUlfkm!"

00007FF69D4015D8  | 75 EB               | jne crackme_c0nstant.7FF69D4015C5    |

00007FF69D4015DA  | 48 8B 4C 24 28      | mov rcx,qword ptr ss:[rsp+28]        |

00007FF69D4015DF  | 48 FF C9            | dec rcx                              | rcx:"~bcyUcyUde~UkUlfkm!"

00007FF69D4015E2  | 48 3B C1            | cmp rax,rcx                          | rcx:"~bcyUcyUde~UkUlfkm!"

00007FF69D4015E5  | 73 20               | jae crackme_c0nstant.7FF69D401607    |

00007FF69D4015E7  | 48 63 44 24 20      | movsxd rax,dword ptr ss:[rsp+20]     |

00007FF69D4015EC  | 48 8B 4C 24 50      | mov rcx,qword ptr ss:[rsp+50]        |

00007FF69D4015F1  | 0F BE 04 01         | movsx eax,byte ptr ds:[rcx+rax]      | rcx+rax*1:"e~UkUlfkm!"

00007FF69D4015F5  | 83 F0 0A            | xor eax,A                            | 여기가 핵심  






코드를 짜보았다.

#include <stdio.h>

#include <string.h>

int main()

{

char fake[] = "~bcyUcyUde~UkUlfkm!";

char *pt = fake;

for (int i = 0; i < strlen(fake)-1; i++)

{

*(pt+i) ^= 0xA;


}

for (int i = 0; i < strlen(fake); i++)

{

printf("%c", fake[i]);

}


} 


디스어셈블에서도 확인하였다.

00007FF69D4015A9  | 89 44 24 20         | mov dword ptr ss:[rsp+20],eax        |

00007FF69D4015AD  | 48 63 44 24 20      | movsxd rax,dword ptr ss:[rsp+20]     |

00007FF69D4015B2  | 48 8B 4C 24 50      | mov rcx,qword ptr ss:[rsp+50]        | [rsp+50]:"this_is_not_a_flag!"

00007FF69D4015B7  | 48 89 4C 24 30      | mov qword ptr ss:[rsp+30],rcx        | [rsp+30]:"this_is_not_a_flag!"

00007FF69D4015BC  | 48 C7 44 24 28 FF F | mov qword ptr ss:[rsp+28],FFFFFFFFFF |

00007FF69D4015C5  | 48 FF 44 24 28      | inc qword ptr ss:[rsp+28]            |

00007FF69D4015CA  | 48 8B 4C 24 30      | mov rcx,qword ptr ss:[rsp+30]        | [rsp+30]:"this_is_not_a_flag!"

00007FF69D4015CF  | 48 8B 54 24 28      | mov rdx,qword ptr ss:[rsp+28]        |

00007FF69D4015D4  | 80 3C 11 00         | cmp byte ptr ds:[rcx+rdx],0          |

00007FF69D4015D8  | 75 EB               | jne crackme_c0nstant.7FF69D4015C5    |

00007FF69D4015DA  | 48 8B 4C 24 28      | mov rcx,qword ptr ss:[rsp+28]        |

00007FF69D4015DF  | 48 FF C9            | dec rcx                              |

00007FF69D4015E2  | 48 3B C1            | cmp rax,rcx                          |

00007FF69D4015E5  | 73 20               | jae crackme_c0nstant.7FF69D401607    |

00007FF69D4015E7  | 48 63 44 24 20      | movsxd rax,dword ptr ss:[rsp+20]     |

00007FF69D4015EC  | 48 8B 4C 24 50      | mov rcx,qword ptr ss:[rsp+50]        | [rsp+50]:"this_is_not_a_flag!"

00007FF69D4015F1  | 0F BE 04 01         | movsx eax,byte ptr ds:[rcx+rax]      |

00007FF69D4015F5  | 83 F0 0A            | xor eax,A                            |

00007FF69D4015F8  | 48 63 4C 24 20      | movsxd rcx,dword ptr ss:[rsp+20]     |

00007FF69D4015FD  | 48 8B 54 24 50      | mov rdx,qword ptr ss:[rsp+50]        | [rsp+50]:"this_is_not_a_flag!"

00007FF69D401602  | 88 04 0A            | mov byte ptr ds:[rdx+rcx],al         |

00007FF69D401605  | EB 9C               | jmp crackme_c0nstant.7FF69D4015A3    |

00007FF69D401607  | 48 8B 54 24 50      | mov rdx,qword ptr ss:[rsp+50]        | [rsp+50]:"this_is_not_a_flag!"

00007FF69D40160C  | 48 8D 0D 39 1C 00 0 | lea rcx,qword ptr ds:[7FF69D40324C]  | 7FF69D40324C:"%s\n"


이렇게 짜게 되면, this_is_not_a_flag!가 나오게 된다. 

한가지 알 수 있는 점은 맨 마지막은 xor 취해주지 않았다. 


지금 알게 된 조건 : “this_is_not_a_flag!”가 뜬 것으로 보아 ~bcyUcyUde~UkUlfkm!”는 가짜 플래그 였다.

그렇다면 이제 우리는 ~bcyUcyUde~UkUlfkm!

Char *fake = ~bcyUcyUde~UkUlfkm!”로 복원할 수 있다.




궁금증을 해결했으니, 다시 입력받는 버퍼로 가보자.

입력받기 바로 전 "_NUXALBXOGIGSF]DXFYGZX*+\\PT" 이놈에서 [3] [7] [16] [21] 수정하는 역할을 취한다. 


이놈이 실제 플래그 값인가 보다.


00007FF69D40118E  | E8 5D FF FF FF      | call crackme_c0nstant.7FF69D4010F0   | 문자열을 입력한다

00007FF69D401193  | 89 44 24 20         | mov dword ptr ss:[rsp+20],eax        |

00007FF69D401197  | 48 C7 44 24 28 00 0 | mov qword ptr ss:[rsp+28],0          |

00007FF69D4011A0  | 8B 44 24 20         | mov eax,dword ptr ss:[rsp+20]        |

00007FF69D4011A4  | 48 8B 4C 24 30      | mov rcx,qword ptr ss:[rsp+30]        |

00007FF69D4011A9  | 48 33 CC            | xor rcx,rsp                          |

00007FF69D4011AC  | E8 7F 08 00 00      | call crackme_c0nstant.7FF69D401A30   |

00007FF69D4017DE  | EB 24               | jmp crackme_c0nstant.7FF69D401804    | ------

이 루틴은 딱히 볼 필요가 없었다.                                                                |

                                                                                       |

00007FF69D401804  | 8B 4C 24 5C         | mov ecx,dword ptr ss:[rsp+5C]        |  <----

00007FF69D401808  | E8 63 FD FF FF      | call crackme_c0nstant.7FF69D401570   |


0x7FF69D401570 여기를 들어가보았다.

00007FF69D401570  | 89 4C 24 08         | mov dword ptr ss:[rsp+8],ecx         |

00007FF69D401574  | 83 7C 24 08 04      | cmp dword ptr ss:[rsp+8],4           | 내가 입력한 4와 비교를 하게된다. 

00007FF69D401579  | 74 09               | je crackme_c0nstant.7FF69D401584     | 그렇다면, _의 갯수는 4가 확실하다

00007FF69D40157B  | B8 FF FF FF FF      | mov eax,FFFFFFFF                     |

00007FF69D401580  | EB 07               | jmp crackme_c0nstant.7FF69D401589    |

00007FF69D401582  | EB 05               | jmp crackme_c0nstant.7FF69D401589    |

00007FF69D401584  | B8 01 00 00 00      | mov eax,1                            |

00007FF69D401589  | C3                  | ret                                  | 


그 후 다시 7FF69D401808 다음 명령인 cmp eax,1 로 RIP는 오게 된다

00007FF69D40180D  | 83 F8 01            | cmp eax,1                            | 위의 함수에서 EAX는 1이었으니 

00007FF69D401810  | 0F 85 92 00 00 00   | jne crackme_c0nstant.7FF69D4018A8    |

00007FF69D401816  | C7 44 24 20 00 00 0 | mov dword ptr ss:[rsp+20],0          | 여기로 분기하게 된다

00007FF69D40181E  | EB 0A               | jmp crackme_c0nstant.7FF69D40182A    | -----------------

00007FF69D401820  | 8B 44 24 20         | mov eax,dword ptr ss:[rsp+20]        |                 |

00007FF69D401824  | FF C0               | inc eax                              |                 |

00007FF69D401826  | 89 44 24 20         | mov dword ptr ss:[rsp+20],eax        |                 |

00007FF69D40182A  | 48 63 44 24 20      | movsxd rax,dword ptr ss:[rsp+20]     | <----------------


특정 문구 또 다시 루프 

00007FF69D401844  | 48 FF 44 24 30      | inc qword ptr ss:[rsp+30]            |

00007FF69D401849  | 48 8B 4C 24 48      | mov rcx,qword ptr ss:[rsp+48]        |

00007FF69D40184E  | 48 8B 54 24 30      | mov rdx,qword ptr ss:[rsp+30]        |

00007FF69D401853  | 80 3C 11 00         | cmp byte ptr ds:[rcx+rdx],0          |

00007FF69D401857  | 75 EB               | jne crackme_c0nstant.7FF69D401844    |


00007FF69D40404F   61 61 61 61 00 00 00 00 00 [76 7C 71 77 6B 49 7F    aaaa.....v|qwkI.   

00007FF69D40405F   65 4F 78 24 66 75 4F 43 27 65 74 21 75 74 4F 74    eOx$fuOC'et!utOt   

00007FF69D40406F   79 21 79 77 23 7E 64 21 69 4F 76 7F 62 4F 42 75    y!yw#~d!iOv.bOBu   

00007FF69D40407F   66 23 62 63 79 7E 77 7D] 00 00 00 00 00 00 00 00    f#bcy~w}........   


만약 under_bar 갯수를 4개로 지정하지 않았다면 메시지박스가 또 뜨게 될 것 이다. 




지금 알게 된 조건 : 특정 배열에서 ‘X’를 찾아서 그것만 특별히xor취해준다.

4개의 X가 존재한다. Xor이후 값은 5F(‘_’) 이다.

배열은 "_NUXALBXOGIGSF]DXFYGZX*+\\PT“

Char *real = "_NUXALBXOGIGSF]DXFYGZX*+\\PT“;




00007FF69D40186E  | 33 C2               | xor eax,edx                          |

00007FF69D401870  | 2B C2               | sub eax,edx                          |

00007FF69D401872  | 85 C0               | test eax,eax                         |

00007FF69D401874  | 74 22               | je crackme_c0nstant.7FF69D401898     | test 연산결과 z플래그가 1이 아니면 xor eax,10을 진행한다

00007FF69D401876  | 48 63 44 24 20      | movsxd rax,dword ptr ss:[rsp+20]     | 즉, 홀수만 xor 10 한다는 것

00007FF69D40187B  | 48 8D 0D D6 27 00 0 | lea rcx,qword ptr ds:[7FF69D404058]  | rcx:"aa_aaa_aaaaaaaa_aaaa_aaaaaa"

00007FF69D401882  | 0F BE 04 01         | movsx eax,byte ptr ds:[rcx+rax]      | rcx+rax*1:"aaaaa_aaaa_aaaaaa"

00007FF69D401886  | 83 F0 10            | xor eax,10                           | 이 부분이 아주 중요한 부분이다. 

00007FF69D401889  | 48 63 4C 24 20      | movsxd rcx,dword ptr ss:[rsp+20]     |

00007FF69D40188E  | 48 8D 15 C3 27 00 0 | lea rdx,qword ptr ds:[7FF69D404058]  |

00007FF69D401895  | 88 04 0A            | mov byte ptr ds:[rdx+rcx],al         | rdx+rcx*1:"aa_aaa_aaaaaaaa_aaaa_aaaaaa"

00007FF69D401898  | EB 86               | jmp crackme_c0nstant.7FF69D401820    |

 


c코드 

#include <stdio.h>

#include <string.h>

int main()

{

char result_flag[] = { "v|qwkIeOx$fuOC'et!utOty!yw#~d!iOvbOBuf#bcy~w}" };

for (int j = 0; j < strlen(result_flag); j++)

{

if (j % 2 != 0)

{

result_flag[j] ^= 0x10;

}

}

for (int j = 0; j < strlen(result_flag); j++)

{

printf("%c", result_flag[j]);

}

printf("\n");

return 0;

} 


현재 까지 복원 상태 

vlqgkYuOh$vu_C7ed!et_ti!iw3~t!yOfrORuv#rci~g} 



0x3, 0x7, 0x10, 0x15 에 '_'가 들어 있는지 검사한다.


허걱 디버깅 하다보니 [0]부터 시작인데 [1]부터 갯수를 세어 _위치가 이상하게 되어있음을 발견했다. 


배열은 [0]부터 시작인데 숫자 3만 신경 쓰다가 3번째 자리에 _를 적어두는 불상사가 발생했다. 
괜찮다. 실수하면서 느는거다....ㅠㅠ



본격적으로 내가 입력한 값에 대한 연산을 체크한다. 우선, 널 까지 쭉 확인

00007FF69D4013F1  | 89 44 24 20         | mov dword ptr ss:[rsp+20],eax        |

00007FF69D4013F5  | 48 63 44 24 20      | movsxd rax,dword ptr ss:[rsp+20]     |

00007FF69D4013FA  | 48 8B 4C 24 50      | mov rcx,qword ptr ss:[rsp+50]        | [rsp+50]:"aa_aaa_aaaaaaaa_aaaa_aaaaaa"

00007FF69D4013FF  | 48 89 4C 24 30      | mov qword ptr ss:[rsp+30],rcx        | [rsp+30]:"aa_aaa_aaaaaaaa_aaaa_aaaaaa"

00007FF69D401404  | 48 C7 44 24 28 FF F | mov qword ptr ss:[rsp+28],FFFFFFFFFF |

00007FF69D40140D  | 48 FF 44 24 28      | inc qword ptr ss:[rsp+28]            |

00007FF69D401412  | 48 8B 4C 24 30      | mov rcx,qword ptr ss:[rsp+30]        | [rsp+30]:"aa_aaa_aaaaaaaa_aaaa_aaaaaa"

00007FF69D401417  | 48 8B 54 24 28      | mov rdx,qword ptr ss:[rsp+28]        |

00007FF69D40141C  | 80 3C 11 00         | cmp byte ptr ds:[rcx+rdx],0          | rcx+rdx*1:"aa_aaa_aaaaaaaa_aaaa_aaaaaa"

00007FF69D401420  | 75 EB               | jne crackme_c0nstant.7FF69D40140D    |


00007FF69D40142F  | 83 7C 24 20 03      | cmp dword ptr ss:[rsp+20],3          | // index

00007FF69D401434  | 75 13               | jne crackme_c0nstant.7FF69D401449    |

00007FF69D401436  | 48 63 44 24 20      | movsxd rax,dword ptr ss:[rsp+20]     |

00007FF69D40143B  | 48 8B 4C 24 50      | mov rcx,qword ptr ss:[rsp+50]        | [rsp+50]:"aa_aaa_aaaaaaaa_aaaa_aaaaaa"

00007FF69D401440  | 0F BE 04 01         | movsx eax,byte ptr ds:[rcx+rax]      |

00007FF69D401444  | 83 F8 5F            | cmp eax,5F                           | 5F:'_'

00007FF69D401447  | 74 4E               | je crackme_c0nstant.7FF69D401497     |

00007FF69D401449  | 83 7C 24 20 07      | cmp dword ptr ss:[rsp+20],7          | // index

00007FF69D40144E  | 75 13               | jne crackme_c0nstant.7FF69D401463    |

00007FF69D401450  | 48 63 44 24 20      | movsxd rax,dword ptr ss:[rsp+20]     |

00007FF69D401455  | 48 8B 4C 24 50      | mov rcx,qword ptr ss:[rsp+50]        | [rsp+50]:"aa_aaa_aaaaaaaa_aaaa_aaaaaa"

00007FF69D40145A  | 0F BE 04 01         | movsx eax,byte ptr ds:[rcx+rax]      |

00007FF69D40145E  | 83 F8 5F            | cmp eax,5F                           | 5F:'_'

00007FF69D401461  | 74 34               | je crackme_c0nstant.7FF69D401497     |

00007FF69D401463  | 83 7C 24 20 10      | cmp dword ptr ss:[rsp+20],10         | // index

00007FF69D401468  | 75 13               | jne crackme_c0nstant.7FF69D40147D    |

00007FF69D40146A  | 48 63 44 24 20      | movsxd rax,dword ptr ss:[rsp+20]     |

00007FF69D40146F  | 48 8B 4C 24 50      | mov rcx,qword ptr ss:[rsp+50]        | [rsp+50]:"aa_aaa_aaaaaaaa_aaaa_aaaaaa"

00007FF69D401474  | 0F BE 04 01         | movsx eax,byte ptr ds:[rcx+rax]      |

00007FF69D401478  | 83 F8 5F            | cmp eax,5F                           | 5F:'_'

00007FF69D40147B  | 74 1A               | je crackme_c0nstant.7FF69D401497     |

00007FF69D40147D  | 83 7C 24 20 15      | cmp dword ptr ss:[rsp+20],15         | // index

00007FF69D401482  | 75 1F               | jne crackme_c0nstant.7FF69D4014A3    | 


재시작.


input : aaa_aaa_aaaaaaaa_aaaa_aaaaa



이번엔 제대로 값이 들어가서 첨자를 정확하게 비교 할 수 있다.





위의 루틴에서 [rsp+24]가 4 즉, 4개의 underscore + 정확한 위치 선정 했으면 함수를 빠져 나갈 수 있다.

00007FF69D4014AD  | 83 7C 24 24 04      | cmp dword ptr ss:[rsp+24],4          |

00007FF69D4014B2  | 74 0A               | je crackme_c0nstant.7FF69D4014BE     | -------

.....                                                                                  |

00007FF69D4014BE  | B8 01 00 00 00      | mov eax,1                            | <-----|

00007FF69D4014C3  | 48 83 C4 48         | add rsp,48                           |

00007FF69D4014C7  | C3                  | ret                                  |


00007FF69D401915  | 83 F8 01            | cmp eax,1                            |

00007FF69D401918  | 0F 85 A3 00 00 00   | jne crackme_c0nstant.7FF69D4019C1    |

00007FF69D40191E  | 48 8D 0D EB 19 00 0 | lea rcx,qword ptr ds:[7FF69D403310]  | rcx:"Correct !!! \n", 7FF69D403310:"Correct !!! \n"

00007FF69D401925  | E8 46 F7 FF FF      | call crackme_c0nstant.7FF69D401070   |


......

00007FF69D401070  | 48 89 4C 24 08      | mov qword ptr ss:[rsp+8],rcx         | [rsp+8]:"Correct!!\n"

00007FF69D401075  | 48 89 54 24 10      | mov qword ptr ss:[rsp+10],rdx        |

00007FF69D40107A  | 4C 89 44 24 18      | mov qword ptr ss:[rsp+18],r8         |

00007FF69D40107F  | 4C 89 4C 24 20      | mov qword ptr ss:[rsp+20],r9         |

00007FF69D401084  | 48 83 EC 48         | sub rsp,48                           |

00007FF69D401088  | 48 8B 05 79 2F 00 0 | mov rax,qword ptr ds:[7FF69D404008]  |

00007FF69D40108F  | 48 33 C4            | xor rax,rsp                          |

00007FF69D401092  | 48 89 44 24 30      | mov qword ptr ss:[rsp+30],rax        |

00007FF69D401097  | E8 74 09 00 00      | call crackme_c0nstant.7FF69D401A10   |


......

00007FF69D401932  | EB 0A               | jmp crackme_c0nstant.7FF69D40193E    |

00007FF69D401934  | 8B 44 24 24         | mov eax,dword ptr ss:[rsp+24]        |

00007FF69D401938  | FF C0               | inc eax                              |

00007FF69D40193A  | 89 44 24 24         | mov dword ptr ss:[rsp+24],eax        |

00007FF69D40193E  | 48 63 44 24 24      | movsxd rax,dword ptr ss:[rsp+24]     |


여기 보면 이번엔 짝수만 xor 10 한다.

00007FF69D40198F  | 48 8D 0D C2 26 00 0 | lea rcx,qword ptr ds:[7FF69D404058]  |

00007FF69D401996  | 0F BE 04 01         | movsx eax,byte ptr ds:[rcx+rax]      |

00007FF69D40199A  | 83 F0 10            | xor eax,10                           |

00007FF69D40199D  | 48 63 4C 24 24      | movsxd rcx,dword ptr ss:[rsp+24]     |

00007FF69D4019A2  | 48 8D 15 AF 26 00 0 | lea rdx,qword ptr ds:[7FF69D404058]  |

00007FF69D4019A9  | 88 04 0A            | mov byte ptr ds:[rdx+rcx],al         |

00007FF69D4019AC  | EB 86               | jmp <crackme_c0nstant.sub_7FF69D4019 |

 


c코드

#include <stdio.h>

#include <string.h>

int main()

{

char result_flag[] = { "v|qwkIeOx$fuOC'et!utOty!yw#~d!iOvbOBuf#bcy~w}" };

for (int j = 0; j < strlen(result_flag); j++)

{

if (j % 2 != 0)

{

result_flag[j] ^= 0x10;

}

}

for (int j = 0; j < strlen(result_flag)-1; j++)

{

if (j % 2 == 0)

{

result_flag[j] ^= 0x10;

}

}

for (int j = 0; j < strlen(result_flag); j++)

{

printf("%c", result_flag[j]);

}

printf("\n");

return 0;

}

flag{You_h4ve_S7ud1ed_di1ig3nt1y_for_Rev3rsing}

 




사실상 내가 만든 문제지만, 입력값은 정확하게 도출하지 않아도 플래그는 나온다..

메시지박스에서 복호화를 진행시켰기 때문이다....

담엔 더 어렵게 만들어야지.



그래도 입력값도 구경하자.

00007FF69D401250  | 48 89 54 24 10      | mov qword ptr ss:[rsp+10],rdx        |

00007FF69D401255  | 48 89 4C 24 08      | mov qword ptr ss:[rsp+8],rcx         |

00007FF69D40125A  | 48 83 EC 58         | sub rsp,58                           |

00007FF69D40125E  | C7 44 24 28 00 00 0 | mov dword ptr ss:[rsp+28],0          |

00007FF69D401266  | B8 01 00 00 00      | mov eax,1                            |

00007FF69D40126B  | 48 6B C0 00         | imul rax,rax,0                       |

00007FF69D40126F  | 48 8B 4C 24 60      | mov rcx,qword ptr ss:[rsp+60]        |

00007FF69D401274  | C6 04 01 59         | mov byte ptr ds:[rcx+rax],59         | 59:'Y'

00007FF69D401278  | C7 44 24 20 01 00 0 | mov dword ptr ss:[rsp+20],1          |

00007FF69D401280  | EB 0A               | jmp crackme_c0nstant.7FF69D40128C    |-------

00007FF69D401282  | 8B 44 24 20         | mov eax,dword ptr ss:[rsp+20]        |      |

00007FF69D401286  | FF C0               | inc eax                              |      | 

00007FF69D401288  | 89 44 24 20         | mov dword ptr ss:[rsp+20],eax        |      |

00007FF69D40128C  | 48 63 44 24 20      | movsxd rax,dword ptr ss:[rsp+20]     |<------

00007FF69D401291  | 48 8B 4C 24 60      | mov rcx,qword ptr ss:[rsp+60]        |

00007FF69D401296  | 48 89 4C 24 40      | mov qword ptr ss:[rsp+40],rcx        | [rsp+40]:"aaa_aaa_aaaaaaaa_aaaa_aaaaa"

00007FF69D40129B  | 48 C7 44 24 30 FF F | mov qword ptr ss:[rsp+30],FFFFFFFFFF |

00007FF69D4012A4  | 48 FF 44 24 30      | inc qword ptr ss:[rsp+30]            | <-----------------------------------------

00007FF69D4012A9  | 48 8B 4C 24 40      | mov rcx,qword ptr ss:[rsp+40]        | [rsp+40]:"aaa_aaa_aaaaaaaa_aaaa_aaaaa"  |

00007FF69D4012AE  | 48 8B 54 24 30      | mov rdx,qword ptr ss:[rsp+30]        |                                         |

00007FF69D4012B3  | 80 3C 11 00         | cmp byte ptr ds:[rcx+rdx],0          |                                         |

00007FF69D4012B7  | 75 EB               | jne crackme_c0nstant.7FF69D4012A4    | ----------------------------------------

......

00007FF69D4012D4  | 83 F8 5F            | cmp eax,5F                           | 5F:'_'

00007FF69D4012D7  | 75 04               | jne crackme_c0nstant.7FF69D4012DD    |

00007FF69D4012D9  | EB A7               | jmp crackme_c0nstant.7FF69D401282    |

00007FF69D4012DB  | EB 42               | jmp crackme_c0nstant.7FF69D40131F    |

00007FF69D4012DD  | 48 63 44 24 20      | movsxd rax,dword ptr ss:[rsp+20]     |

00007FF69D4012E2  | 8B 4C 24 20         | mov ecx,dword ptr ss:[rsp+20]        |

00007FF69D4012E6  | 83 C1 03            | add ecx,3                            |

00007FF69D4012E9  | 48 8B 54 24 60      | mov rdx,qword ptr ss:[rsp+60]        | [rsp+60]:"YOU_CLB_OGIGSF]D_FYGZ_*+\\PT"

00007FF69D4012EE  | 0F BE 04 02         | movsx eax,byte ptr ds:[rdx+rax]      |

00007FF69D4012F2  | 33 C1               | xor eax,ecx                          | EAX^=ECX+3

00007FF69D4012F4  | 48 63 4C 24 20      | movsxd rcx,dword ptr ss:[rsp+20]     |

00007FF69D4012F9  | 48 8B 54 24 60      | mov rdx,qword ptr ss:[rsp+60]        | [rsp+60]:"YOU_CLB_OGIGSF]D_FYGZ_*+\\PT"

00007FF69D4012FE  | 88 04 0A            | mov byte ptr ds:[rdx+rcx],al         | rdx+rcx*1:"SF]D_FYGZ_*+\\PT"

00007FF69D401301  | 48 63 44 24 20      | movsxd rax,dword ptr ss:[rsp+20]     |

00007FF69D401306  | 48 8B 4C 24 60      | mov rcx,qword ptr ss:[rsp+60]        | [rsp+60]:"YOU_CLB_OGIGSF]D_FYGZ_*+\\PT"

00007FF69D40130B  | 0F BE 04 01         | movsx eax,byte ptr ds:[rcx+rax]      | rcx+rax*1:"LB_OGIGSF]D_FYGZ_*+\\PT"

00007FF69D40130F  | 83 F0 05            | xor eax,5                            |


배열[0]에는 Y그냥 대입, 5F면 무시하고 지나가고, 다른 값에선 eax^=(i+3) 과 eax^=5 값을하면 된다. 


input 코드

#include <stdio.h>

#include <string.h>

int main()

{

char real_key[] = { "_NUXALBXOGIGSF]DXFYGZX*+\\PT" };

real_key[0] = 'Y';


for (int j = 0 ; j < strlen(real_key); j++ )

{

if (real_key[j] == 'X')

{

real_key[j] = '_';

}

}


for (int j = 0; j < strlen(real_key)-1; j++)

{

if (real_key[j] == '_')

{

continue;

}

if (j == 0)

continue;

else

{

real_key[j] ^= (j + 3);

real_key[j] ^= 0x5;


}

}

for (int j = 0; j < strlen(real_key); j++)

{

printf("%c", real_key[j]);

}


printf("\n");

return 0;

} 



흐아.. 다음부터는 워드에 작성하겠습니다.



요약


'0x02 Reverse Engineer > 0x03. Etc' 카테고리의 다른 글

suninatas 10번 문제  (0) 2017.12.30
[리버싱과 무관할수도] 백준 난쟁이문제 - bruteforce  (0) 2017.12.16
처음 만들어 본 64비트 크랙미 분석  (0) 2017.11.30
Inline Assembly  (0) 2017.10.30
[H4C] BINGO BINARY  (0) 2017.10.28
[LENA 3] Let's patch nag !  (0) 2017.10.23
0 Comments
댓글쓰기 폼