-
0x64 ^ 0x21
입력값을 한글자 한글자 확인하고, 길이를 확인하는 부분
0x0A랑 비교하는걸 보니 input값이 10글자여야 하는듯
바로 다음인 여기서 에러가 뜬다.
무한루프에 돌게 된다...
그래서
돌려보면 무한루프에 빠져서 원래는 Correct나 Wrong이 나타나야 하는 데 안 나타나는 듯 ㅇㅇ...
여기서 안티디버깅 기법에 대해서 아래 블로그에서 정보를 얻었는 데...
https://ruinick.tistory.com/27
이 부분의 결과값으로 ntdll_NtQueryInformationProcess 를 받길래 찾다 보니 위 블로그에서 본 안티 디버깅 기법이 들어간 것 같다.
수도코드로 보면 위와 같은 데...
이 조건을 통과해야 루프에 돌지 않는다 ㅇㅇ..
자 그럼 저 인자로 포인터를 넘겨주는 데, 포인터의 값이 0xB8이랑 5번째 값이 0xBA여야 하니까..
(char*)*409150 = 0xB8 이어야 하고, *409155 = 0xBA여야 한다.....
새로운 사실을 알았다.
중요사진1.에서 sub_401090의 함수의 매개변수로 40B968을 가져가는 데 이곳에 적힌 값이 ntdll이다. 그리고 아마 두번째 매개변수로 함수의 이름을 받아가는 것 같다. 그리고 저 함수가 실제로 로드 됬는 지 확인하는 부분이 그 다음 사진 인거같다.
왜냐면 함수를 그대로 포인터 작업을 통해서 옮겨 놓으니까 ㅇㅇ..
지금 근데 진짜 도대체 뭐가 안되나?? 하고 계속 고민을 했는 데...
이게 힌트 인거같다... 내 윈도우가 64비트다 보니까 지금 ntdll에서 함수 가져오는ㄷ ㅔ
ZwQueryInformationfile 이함수 가져오거든요?? 근데 분명히 가져왔는 데, 저 B8 BA 이부분을 통과를 못하는 거예여... 근데 저게 사실은 함수들이 다 push ebp mov ebp esp 어쩌구로 시작하는 데 그부분에 대한 거라서 당연히 통과를 해야하는 데 왜 못통과를 하나? 하고 도저히 이상한게 없다고 생각했는 ㅔㄷ, 마지막 힌트가 이거인듯... 하ㅣ바..
내일해야하나...
해결했다.
Window7 32bit 가상머신을 깔고나서... 거기서 실행을 하니까 정상적으로 실행되더라... 64비트에서 실행하면 안됨... ;;;
그래서 원래 쓰던 아이다를 포기하고...
x64dbg를 옮겨서 사용하였다...
좋은 디버거 쓰다가 이런거 쓰려니까 매우 힘들군..
하여튼,,
나는 항상 어떤 패킹되어 있는 파일을 분석할 때는 패킹을 직접 푸는 것보다는 그냥 실행을 하고나서 ATTACH하는 것을 좋아한다. 그래서 이번 문제도 계속 실행하고 ATTACH하는 것으로 접근할 것이다.
제대로 실행이 되니까 처음부터 다시 문제를 풀었다.
실행을 시켜두고, 덤프파일을 만들었다.
덤프파일은 특정한 툴 없이도 작업관리자에서도 된다 ㅇㅇ..
그다음 덤프파일을 통해서 IDA로 정적 분석을 진행하고, 그것과 비교하면서 x64디버거로 가상머신에서 리버싱을 할 것이다.
다시,,,
이 문제는 check 하는 과정이 있어서 그 과정에서 input이 맞는 지 혹은 틀렸는 지 확인하는 과정이 있었고, 아래 사진에서 bp를 걸어둔 곳만 분석하면 된다.
bp를 걸어둔 곳의 함수 수도 코드는 아래와 같다.
중간중간 제대로 디컴파일이 되지 않은 부분도 있지만, 이정도는 어셈블리로 분석하고 이만큼 분석해준다는 거에 감사하도록 하자.
// write access to const memory has been detected, the output may be wrong! // positive sp value has been detected, the output may be wrong! char sub_401240() { int i; // eax char v1; // cl _DWORD *v2; // eax _BYTE *v3; // ecx int v5; // eax HANDLE Thread; // eax char v7; // al int v8; // [esp-70h] [ebp-7Ch] int v9; // [esp-1Ch] [ebp-28h] char v10[12]; // [esp+0h] [ebp-Ch] for ( i = 0; i < 10; ++i ) { v1 = *((_BYTE *)&dword_40B970 + i); if ( !v1 ) break; v10[i] = v1; } v2 = (_DWORD *)dll_addr(ntdll_off, aZwqueryinforma); *(_DWORD *)&query_dll = *v2; ++v2; *((_DWORD *)&query_dll + 1) = *v2; ++v2; *((_DWORD *)&query_dll + 2) = *v2; *((_DWORD *)&query_dll + 3) = v2[1]; if ( dll_check(&query_dll) ) return dll_check(v3); debug = 0; ((void (__cdecl *)(int, int, int *, int, _DWORD))query_dll)(-1, 7, &debug, 4, 0);// 디버깅 중이면 debug에 -1반환 if ( debug ) { sub_402050(debug == 0, (int)&v9); goto LABEL_10; } debug = 0; if ( ((int (__cdecl *)(int, int, int *, int, _DWORD, int))query_dll)(-1, 0x1E, &debug, 4, 0, 0x4072A8) == 0xC0000353 )// 디버깅 중이면 debug에 0이 아닌 값 반환, 리턴값이 0 { if ( query_dll == (char)0xB8 ) { v8 = 0; LABEL_14: not_debug = 0; ((void (__cdecl *)(int, int, int *, int, int))query_dll)(-1, 0x1F, ¬_debug, 4, v8);// 디버깅 중이면 not_debug 가 0 반환 while ( not_debug ) { sub_407405(); *((_BYTE *)sub_407405 + 2) = 0x80; *(&loc_40740B + 2) = 0x81; *(&loc_407411 + 2) = 0x90; *(&loc_407417 + 2) = 0x91; byte_40C450 = byte_40B991 ^ 0x36; qmemcpy(&ft_text, "GetCurrentThread", 16); loc_407471 = 0x15975623; *(&loc_407471 + 1) = 0x1ABCD562; loc_40749A = 0x1A25CFDA; loc_40748E = 0x9CA565AA; v5 = dll_addr(dll__, (char *)&ft_text); qmemcpy(&ft_text, "GetThreadContext", 16); loc_4074EF = 0x15975623; loc_4074F5 = 0x1ABCD562; *(&loc_407400 + 1) = 0x1A25CFDA; loc_4074AE = 0x9CA565AA; *(_DWORD *)GetCurrentThread = v5; GetThreadContex_ = dll_addr(dll__, (char *)&ft_text); Thread = GetCurrentThread(); a2 = 0x1001F; ((void (__cdecl *)(HANDLE, int *))GetThreadContex_)(Thread, &a2); if ( dword_4092A4 ) break; ft_text = 0; dword_409204 = 0; dword_409208 = 0; dword_40920C = 0; loc_407564 = 0xC705AE74; if ( dword_4092A8 ) goto LABEL_14; if ( dword_4092AC ) JUMPOUT(0x40744C); if ( !dword_4092B0 ) { if ( dword_4092B4 ) JUMPOUT(0x407466); if ( dword_4092B8 ) JUMPOUT(0x407473); if ( byte_40C450 != '6' ) return 0; v7 = ((int (*)(void))loc_40762B)(); return sub_407619(v7); } } goto LABEL_11; } LABEL_10: JUMPOUT(0x407306); } LABEL_11: MEMORY[0xDB402080](); return sub_407405(); }
코드는 위와 같다.
중간중간 안티디버깅 과정이 있는 데,
이 부분들이다. 이 부분들은 ntdll_NtQueryInformationProcess 함수를 이용해서 안티 디버깅을 해둔 것으로 아까 위에서 참고할 만한 블로그들을 올려두었다.
안티디버깅을 잘 피하고 나면
이 부분에 도달한다.
여기서 보면, 복잡해 보이지만 결국에는 GetCurrentThread 과정과 GetThreadContext과정과 코드부분을 패킹하는 과정이다. 그리고 이후 맨 아래쪽에
이 부분이 있는 데, GetThreadContext함수를 아래 블로그에서 확인하고 가자.
즉, 지금 실행되고 있는 Thread에서 Context 정보들을 다 적절히 잘 저장하고
그 값들에 대해서 if문에서 대조를 하면서 통과를 하고 있는 것으로 보인다.
근데, Context에 대한 것들은 다 그냥 통과하더라 ㅇㅇ...
마지막에 byte_40c450 != '6' 이부분이 통과가 되지 않아서 조금더 분석하기로 한다.
제가 조금 더 분석을 해보고 왔습니다. 저 마지막에 loc_40762B는 인자로 al에다가 뭔가를 넣더라구요?
근데 아무리 생각해도 저게 뭔가 중요한거 같아서 저 값들이 언제 정해지는 지 확인을 해봤는 데,
여기서 맨위에 함수 key_setting이라고 명명해 둔곳에서 정해지더군요.. (참고로 위에 사진에서는 그냥 함수 주소로 써져있음) key라고 되어있는 거의 경우에는 위 사진에서 6이랑 비교하는 값이고, 그 값을 xor해주길래 xor해주는 값을 key1이라 했습니다. 또, 2개 위 사진에서 mov al, key2 해주는 변수 key2라 해줬고요.
근데 두 문자 둘다 input_text에 의해서 정해지더군요...
일단 알고 가자구요..
그런다음 마지막 함수
loc_40762b()라고 되어 있는 것이
어셈블리로 위와 같더군요.
혹시 몰라서 바로 아래 함수를 last_2 라고 하긴 했는 데... 보시면 push ebp, mov ebp, esp가 없죠? 그럼 함수 호출규약에 맞지 않아서 last_2까지 안갈거예요...
last함수는 이 과정을 지낸 다음에,, ret을 하네요..
참고로 ror 어셈블리는 rotate right 어셈블리로 쉬프트 하는 거예요.
이제 리턴을 하면
처음에
여기로 돌아가는 데, 이 리턴 값이 0이 아니면 correct라고 뜨네요 !!! 후....
분석을 다했군요...
정리하자면, 맨 마지막에는 input[0]을 rotate right 6을 한다. 이를 40B000에다가 저장하고 또 4번 돌리고
40B001에 저장하고, 0x34랑 xor해서 40b003에 저장한다.
그리고 새로운 사실... 디버거로 그냥 보내봤더니... last_2로 가네요... 역시 마지막까지 끝난게 아니야..
아진짜 개노가다네...
하...
이후 과정은 생략하도록 하겠음... 그냥 ㅈㄴ 노가다임..
이거 여러번 디버거로 돌려본다음 생각해봤는 데, 디컴파일코드나 아이다 보는 것보다 그냥 어셈블리로 보는게 훨씬 편하네..
마지막까지 포스트를 봐준 분들께.. 제가 어셈블리로 열심히 정리한 선물을 드림...
이게 각 어셈블리 사이에 쓸데없는 어셈블리들이 엄청 많아서 풀면서도 너무 힘듬
0040760F | A0 90B94000 | mov al,byte ptr ds:[40B990] | 40B990 : input[0] 0040762D | C0C8 06 | ror al,6 | 00407630 | A2 00B04000 | mov byte ptr ds:[40B000],al | 00407619 | C0C0 04 | rol al,4 | 0040761C | A2 01B04000 | mov byte ptr ds:[40B001],al | 00407621 | 34 34 | xor al,34 | 00407623 | A2 02B04000 | mov byte ptr ds:[40B002],al | 00407700 | 8A0D 00B04000 | mov cl,byte ptr ds:[40B000] | 004076D0 | 80F9 49 | cmp cl,49 | 49:'I' 004076E4 | 33C0 | xor eax,eax | 004076E6 | 33C9 | xor ecx,ecx | 004076E9 | A0 70B94000 | mov al,byte ptr ds:[40B970] | 0040B970:"asdfas" : input 004076EE | 8A15 71B94000 | mov dl,byte ptr ds:[40B971] | 0040B971:"sdfas" 004076F4 | 8A0D 72B94000 | mov cl,byte ptr ds:[40B972] | 0040B972:"dfas" 0040771B | 8A35 73B94000 | mov dh,byte ptr ds:[40B973] | 0040B973:"fas" 00407721 | 8A3D 74B94000 | mov bh,byte ptr ds:[40B974] | 0040B974:"as" 00407727 | 8A1D 75B94000 | mov bl,byte ptr ds:[40B975] | 0040772D | 8335 70B94000 12 | xor dword ptr ds:[40B970],12 | 0040B970:"asdfas" 00407750 | 880D E0CC4000 | mov byte ptr ds:[40CCE0],cl | 00407756 | 881D E4CC4000 | mov byte ptr ds:[40CCE4],bl | 0040775C | A2 E8CC4000 | mov byte ptr ds:[40CCE8],al | 00407761 | 8815 ECCC4000 | mov byte ptr ds:[40CCEC],dl | 00407771 | 883D F0CC4000 | mov byte ptr ds:[40CCF0],bh | 00407777 | 8835 F4CC4000 | mov byte ptr ds:[40CCF4],dh | 0040777D | 33C0 | xor eax,eax | 0040777D | 33C0 | xor eax,eax | 0040777F | 8BC8 | mov ecx,eax | 00407781 | 8BD0 | mov edx,eax | 00407783 | A0 E0CC4000 | mov al,byte ptr ds:[40CCE0] | 00407788 | 34 77 | xor al,77 | 004077A3 | 3C 35 | cmp al,35 | 35:'5' 00407800 | 8B0D ECCC4000 | mov ecx,dword ptr ds:[40CCEC] | 00407806 | 890D 80CD4000 | mov dword ptr ds:[40CD80],ecx | 0040780C | 8B0D 80CD4000 | mov ecx,dword ptr ds:[40CD80] | 004077AC | 80F1 20 | xor cl,20 | 004077C5 | 80F9 69 | cmp cl,69 | 69:'i' 004077D1 | 8B15 F0CC4000 | mov edx,dword ptr ds:[40CCF0] | 004077D7 | 8915 30CD4000 | mov dword ptr ds:[40CD30],edx | 004077EC | 8A15 E8CC4000 | mov dl,byte ptr ds:[40CCE8] | 00407814 | 80F2 10 | xor dl,10 | 00407817 | 80FA 43 | cmp dl,43 | 43:'C'
하아....
이거 이뒤로는 분석이 안되서 보니까...
여기까지 분석된걸 제대로 넣어주면 또 패킹을 풀면서 다음거로 넘어감 ;;;;;
00407838 | 33C0 | xor eax,eax | 0040783A | 33C9 | xor ecx,ecx | 0040783C | 33D2 | xor edx,edx | 0040783E | 8A15 F4CC4000 | mov dl,byte ptr ds:[40CCF4] | 00407844 | 8AC2 | mov al,dl | 00407846 | A2 00C44000 | mov byte ptr ds:[40C400],al | ? 00407829 | 8A15 00C44000 | mov dl,byte ptr ds:[40C400] | 00407872 | 8A0D 00C44000 | mov cl,byte ptr ds:[40C400] | 00407878 | 880D 01C44000 | mov byte ptr ds:[40C401],cl | 0040787E | 33C0 | xor eax,eax | 00407880 | 33C9 | xor ecx,ecx | 0040778C | 8A0D E4CC4000 | mov cl,byte ptr ds:[40CCE4] | 00407792 | 880D F4CF4000 | mov byte ptr ds:[40CFF4],cl | 0040789E | 58 | pop eax | 0040789F | 59 | pop ecx | 004078A0 | 5A | pop edx | 004078B4 | B9 70AB4000 | mov ecx,twist1.40AB70 | 004078CD | 8901 | mov dword ptr ds:[ecx],eax | 004078BB | 41 | inc ecx | ecx:"w@" 004078BC | 40 | inc eax | 004078D1 | 81F9 00AC4000 | cmp ecx,twist1.40AC00 | ecx:"w@" 004078FD | 33D2 | xor edx,edx | 0040790E | 8A15 01C44000 | mov dl,byte ptr ds:[40C401] | 00407914 | 80F2 21 | xor dl,21 | 00407918 | 80FA 64 | cmp dl,64 | 64:'d' 00407DCE | 8A15 30CD4000 | mov dl,byte ptr ds:[40CD30] | 00407DD4 | 33C0 | xor eax,eax | 00407DD6 | 33FF | xor edi,edi | 00407DD8 | 33C9 | xor ecx,ecx | ecx:"w@" 00407E10 | 33F6 | xor esi,esi | 00407E12 | 52 | push edx | 00407E13 | 58 | pop eax | 00407E14 | 50 | push eax | 00407E15 | 59 | pop ecx | 00407E02 | 80F2 46 | xor dl,46 | 00407DE9 | 52 | push edx | 00407DF6 | 59 | pop ecx | 00407DF7 | 51 | push ecx | 00407E18 | 5A | pop edx | ##이줄 살짝 안 맞는 데 아마도 push edx가 있었을듯 00407E19 | 58 | pop eax | 00407E1A | 3C 08 | cmp al,8 | 00407E1E | 5A | pop edx | 004078A6 | C005 F4CF4000 04 | rol byte ptr ds:[40CFF4],4 | 004078C1 | C605 A6784000 20 | mov byte ptr ds:[4078A6],20 | 20:' ' 00407F6E | 33C0 | xor eax,eax | 00407F77 | 8A15 F4CF4000 | mov dl,byte ptr ds:[40CFF4] | 00407F84 | 80FA 14 | cmp dl,14 |
이렇게 추가로 나오네요 ^^... 하.... 진짜 뭣같네요...
정말 한숨 많이 나오는 문제인데... 이렇게 끈기 있게 풀어서 너무 주옥같습니다.
하.....
input = [0x52, 0x69 ^ 0x20, 0x35 ^ 0x77, ****, 0x8 ^ 0x46, 0x41]
for i in range(6): print(chr(input[i]),end='')이걸 보다니... 이거 돌리면 나오긴 해요
'Writeup > Wargame_Writeup' 카테고리의 다른 글
[ Reversing.kr ] Multiplicative (0) 2020.04.08 [ Reversing.kr ] flashenc (0) 2020.04.08 [ Reversing.kr ] CSHARP (0) 2020.02.29 [ Reversing.kr ] x64 Lotto Writeup (0) 2020.02.28 [ Reversing.kr ] CSHOP writeup (0) 2020.02.28 댓글