readme::
ReversingKr KeygenMe
Find the Name when the Serial is 76876-77776
This problem has several answers.
Password is ***p
평범하게 키값이랑 시리일 값을 찾는 문제인 것 같다.
올리디로 켜서 시리얼값을 계산하는 루틴을 찾아본다.
열심히 브레이크 걸면서 더듬다가 찾았다. 이거 일부러 모듈검사 안걸릴라고 api는 최소한으로 쓰고 저렇게 함수에 번호 붙여서 쓰더라 ㅡㅡ;
여기까지는 문제가 없었는데 이제 이 루틴을 분석하려는데,,,
루틴이 말도 안되게 길다.. 규칙이 따로 있는것도 아니고
위의 그림에서 보면 루틴 시작이 3317D9인데 끝이
331CC0이다 ㅋㅋ 거진 0x400가까이 된다.
어떻게 할까 고민 열심히 했는데 머리가 나빠서 저걸 하나하나 하진 못하겠고 구글에 찾아보니 psuedo code라는 갓 기능이 있다더라
메서드 리스트를 보니 아까 0x4E7에 제일 가까운(?) 메서드를 하나 찾을 수 있다. (사실 크기가 좀 많이 차이나긴 하는데 이유는 잘 모르겠다... 함수 주소를 보면 올리디버거에서는 주소도 33대인데 여긴 정상적으로 401xxx대임..)
f5를 눌러서 저 함수를 디코드하고 분석을 시작해보자 사실 여기부터 시작이다.
CWnd::GetWindowTextW(a1 + 304, &v50); // GetWindowTextW의 인자로 주소가 전달되고
if ( *(_DWORD *)(v50 - 12) == 4 ) // 글자수를 검사하므로 v50은 NAME이다. ( 첫번 째 입력값 )
{
v3 = 0;
while ( (unsigned __int16)ATL::CSimpleStringT<wchar_t,1>::GetAt(&v50, v3) >= 0x61u // 앞에 붙는게 먼지 몰라도
&& (unsigned __int16)ATL::CSimpleStringT<wchar_t,1>::GetAt(&v50, v3) <= 0x7Au ) // 알파벳인지 검사하는 문장
{
if ( ++v3 >= 4 ) // v3는 Name변수의 인자임 4까지만 검사한다는 뜻
{
LABEL_7:
v4 = 0;
while ( 1 )
{
if ( v1 != v4 )
{
v5 = ATL::CSimpleStringT<wchar_t,1>::GetAt(&v50, v4); // GetAt는 2번째 인자의 인덱스값을 반환하는 함수임
if ( (unsigned __int16)ATL::CSimpleStringT<wchar_t,1>::GetAt(&v50, v1) == v5 ) // Name의 알파벳은 서로 중복될 수 없다.
goto LABEL_2; // 2번 라벨은 죽는 분기임 ( return 0 )
}
if ( ++v4 >= 4 )
{
if ( ++v1 < 4 )
goto LABEL_7;
CWnd::GetWindowTextW(a1 + 420, &v51); // v51은 시리얼 입력값
if ( *(_DWORD *)(v51 - 12) == 11 && (unsigned __int16)ATL::CSimpleStringT<wchar_t,1>::GetAt(&v51, 5) == 45 ) // 45는 아스키로 -임
{
v6 = ATL::CSimpleStringT<wchar_t,1>::GetAt(&v50, 0); // name의 첫글자 v6
v7 = (v6 & 1) + 5; // v7 = (첫글자 & 1 + 5 )
v48 = ((v6 >> 4) & 1) + 5; // ..
v42 = ((v6 >> 1) & 1) + 5; // ..
v44 = ((v6 >> 2) & 1) + 5; // ..
v46 = ((v6 >> 3) & 1) + 5; // ..
v8 = ATL::CSimpleStringT<wchar_t,1>::GetAt(&v50, 1); // name의 둘째글자 v8
v34 = (v8 & 1) + 1; //위의 과정 그대로 한번 더
v40 = ((v8 >> 4) & 1) + 1;
v36 = ((v8 >> 1) & 1) + 1;
v9 = ((v8 >> 2) & 1) + 1;
v38 = ((v8 >> 3) & 1) + 1;
v10 = (wchar_t *)ATL::CSimpleStringT<wchar_t,1>::GetBuffer(&v52); // v10은 문자열 포인터
itow_s(v7 + v9, v10, 0xAu, 10); // v10 = (첫글자 & 1 + 5 ) + (둘째글자>>2 & 1 + 1) 를 문자열로 변환한 값
v11 = ATL::CSimpleStringT<wchar_t,1>::GetAt(&v52, 0); // v11 = v10의 첫글자
if ( (unsigned __int16)ATL::CSimpleStringT<wchar_t,1>::GetAt(&v51, 0) == v11 ) // 시리얼의 첫글자는 v11과 같아야함
{
ATL::CSimpleStringT<wchar_t,1>::ReleaseBuffer(&v52, -1); // 쓴 문자열포인터 정리
v12 = (wchar_t *)ATL::CSimpleStringT<wchar_t,1>::GetBuffer(&v52); // v12는 문자열 포인터
itow_s(v46 + v38, v12, 0xAu, 10); // v12 = (첫글자>>3 & 1 + 5) + (둘째글자>>3 & 1 + 1)
v13 = ATL::CSimpleStringT<wchar_t,1>::GetAt(&v51, 1); // v13 = 시리얼 2째글자
if ( v13 == (unsigned __int16)ATL::CSimpleStringT<wchar_t,1>::GetAt(&v52, 0) ) // 시리얼 2째 글자는 v12와 같아야함
{
ATL::CSimpleStringT<wchar_t,1>::ReleaseBuffer(&v52, -1);
v14 = (wchar_t *)ATL::CSimpleStringT<wchar_t,1>::GetBuffer(&v52);
itow_s(v42 + v40, v14, 0xAu, 10); // v14 = ( 첫글자>>2 & 1 + 5 ) + ( 둘째글자>>4 & 1 + 1 )
v15 = ATL::CSimpleStringT<wchar_t,1>::GetAt(&v51, 2); // v15 = 시리얼 3째 글자
if ( v15 == (unsigned __int16)ATL::CSimpleStringT<wchar_t,1>::GetAt(&v52, 0) ) // 시리얼 3째 글자 v14 첫글자
{
ATL::CSimpleStringT<wchar_t,1>::ReleaseBuffer(&v52, -1);
v16 = (wchar_t *)ATL::CSimpleStringT<wchar_t,1>::GetBuffer(&v52);
itow_s(v44 + v34, v16, 0xAu, 10); // v16 = ( 첫글자>>2 & 1 + 5 ) + ( 둘째글자&1 + 1 )
v17 = ATL::CSimpleStringT<wchar_t,1>::GetAt(&v51, 3);
if ( v17 == (unsigned __int16)ATL::CSimpleStringT<wchar_t,1>::GetAt(&v52, 0) ) // 시리얼 4째 글자 = v16 첫글자
{
ATL::CSimpleStringT<wchar_t,1>::ReleaseBuffer(&v52, -1);
v18 = (wchar_t *)ATL::CSimpleStringT<wchar_t,1>::GetBuffer(&v52);
itow_s(v48 + v36, v18, 0xAu, 10); // v18 = ( 첫글자>>4 & 1 + 5 ) + ( 둘째글자>>1 & 1 + 1 )
v19 = ATL::CSimpleStringT<wchar_t,1>::GetAt(&v51, 4);
if ( v19 == (unsigned __int16)ATL::CSimpleStringT<wchar_t,1>::GetAt(&v52, 0) )// 시리얼 5글자 = v18 첫글자
{
ATL::CSimpleStringT<wchar_t,1>::ReleaseBuffer(&v52, -1); // 이하 분석은 생략 시리얼 반대편 루틴도 같은 알고리즘임
v20 = ATL::CSimpleStringT<wchar_t,1>::GetAt(&v50, 2);
v21 = (v20 & 1) + 5;
v49 = ((v20 >> 4) & 1) + 5;
v43 = ((v20 >> 1) & 1) + 5;
v45 = ((v20 >> 2) & 1) + 5;
v47 = ((v20 >> 3) & 1) + 5;
v22 = ATL::CSimpleStringT<wchar_t,1>::GetAt(&v50, 3);
v35 = (v22 & 1) + 1;
v41 = ((v22 >> 4) & 1) + 1;
v37 = ((v22 >> 1) & 1) + 1;
v23 = ((v22 >> 2) & 1) + 1;
v39 = ((v22 >> 3) & 1) + 1;
v24 = (wchar_t *)ATL::CSimpleStringT<wchar_t,1>::GetBuffer(&v52);
itow_s(v21 + v23, v24, 0xAu, 10);
v25 = ATL::CSimpleStringT<wchar_t,1>::GetAt(&v51, 6);
if ( v25 == (unsigned __int16)ATL::CSimpleStringT<wchar_t,1>::GetAt(&v52, 0) )
{
ATL::CSimpleStringT<wchar_t,1>::ReleaseBuffer(&v52, -1);
v26 = (wchar_t *)ATL::CSimpleStringT<wchar_t,1>::GetBuffer(&v52);
itow_s(v47 + v39, v26, 0xAu, 10);
v27 = ATL::CSimpleStringT<wchar_t,1>::GetAt(&v51, 7);
if ( v27 == (unsigned __int16)ATL::CSimpleStringT<wchar_t,1>::GetAt(&v52, 0) )
{
ATL::CSimpleStringT<wchar_t,1>::ReleaseBuffer(&v52, -1);
v28 = (wchar_t *)ATL::CSimpleStringT<wchar_t,1>::GetBuffer(&v52);
itow_s(v43 + v41, v28, 0xAu, 10);
v29 = ATL::CSimpleStringT<wchar_t,1>::GetAt(&v51, 8);
if ( v29 == (unsigned __int16)ATL::CSimpleStringT<wchar_t,1>::GetAt(&v52, 0) )
{
ATL::CSimpleStringT<wchar_t,1>::ReleaseBuffer(&v52, -1);
v30 = (wchar_t *)ATL::CSimpleStringT<wchar_t,1>::GetBuffer(&v52);
itow_s(v45 + v35, v30, 0xAu, 10);
v31 = ATL::CSimpleStringT<wchar_t,1>::GetAt(&v51, 9);
if ( v31 == (unsigned __int16)ATL::CSimpleStringT<wchar_t,1>::GetAt(&v52, 0) )
{
ATL::CSimpleStringT<wchar_t,1>::ReleaseBuffer(&v52, -1);
v32 = (wchar_t *)ATL::CSimpleStringT<wchar_t,1>::GetBuffer(&v52);
itow_s(v49 + v37, v32, 0xAu, 10);
v33 = ATL::CSimpleStringT<wchar_t,1>::GetAt(&v51, 10);
if ( v33 == (unsigned __int16)ATL::CSimpleStringT<wchar_t,1>::GetAt(&v52, 0) )
{
ATL::CSimpleStringT<wchar_t,1>::ReleaseBuffer(&v52, -1);
ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::~CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(&v52);
ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::~CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(&v51);
ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::~CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(&v50);
return 1;
}
}
}
}
}
}
}
}
}
}
}
goto LABEL_2;
}
}
}
}
}
return 0;
그럼 이제 브루트포싱을 해줄 프로그램을 짜보자.
소문자영단어가 26개이고 마지막 자리는 p이므로 26 * 26 * 26 = 17576 가지 정도 가짓수가 나온다. 굳
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//76876-77776
//50 : name
//51 : s1
//52 : 2진수
int s1[11] = {7,6,8,7,6, 99999, 7,7,7,7,6}; // 시리얼
int ch(int arr[4]) {
wchar_t * buf;
int n1 = arr[0];
int n2 = arr[1];
int n3 = arr[2];
int n4 = arr[3];
int v1, v2, v3, v4, v5;
v1 = (n1 & 1) + 5;
v2 = ((n1 >> 1) & 1) + 5;
v3 = ((n1 >> 2) & 1) + 5;
v4 = ((n1 >> 3) & 1) + 5;
v5 = ((n1 >> 4) & 1) + 5;
int x1, x2, x3, x4, x5;
x1 = (n2 & 1) + 1;
x2 = ((n2 >> 1) & 1) + 1;
x3 = ((n2 >> 2) & 1) + 1;
x4 = ((n2 >> 3) & 1) + 1;
x5 = ((n2 >> 4) & 1) + 1;
_itow(v1 + x3, buf, 0xAu);
int v11 = buf[0] - 48;
//printf("%d\n", v11);
if(s1[0] != v11 ) return 0;
_itow(v4 + x4, buf, 0xAu);
v11 = buf[0] - 48;
if(s1[1] != v11 ) return 0;
_itow(v2 + x5, buf, 0xAu);
v11 = buf[0] - 48;
if(s1[2] != v11 ) return 0;
_itow(v3 + x1, buf, 0xAu);
v11 = buf[0] - 48;
if(s1[3] != v11 ) return 0;
_itow(v5 + x2, buf, 0xAu);
v11 = buf[0] - 48;
if(s1[4] != v11 ) return 0;
int v20 = n3;
v1 = (v20 & 1) + 5;
v2 = ((v20 >> 1) & 1) + 5;
v3 = ((v20 >> 2) & 1) + 5;
v4 = ((v20 >> 3) & 1) + 5;
v5 = ((v20 >> 4) & 1) + 5;
x1 = (n4 & 1) + 1;
x2 = ((n4 >> 1) & 1) + 1;
x3 = ((n4 >> 2) & 1) + 1;
x4 = ((n4 >> 3) & 1) + 1;
x5 = ((n4 >> 4) & 1) + 1;
_itow(v1 + x3, buf, 0xAu);
v11 = buf[0] - 48;
if(s1[6] != v11 ) return 0;
_itow(v4 + x4, buf, 0xAu);
v11 = buf[0] - 48;
if(s1[7] != v11 ) return 0;
_itow(v2 + x5, buf, 0xAu);
v11 = buf[0] - 48;
if(s1[8] != v11 ) return 0;
_itow(v3 + x1, buf, 0xAu);
v11 = buf[0] - 48;
if(s1[9] != v11 ) return 0;
_itow(v5 + x2, buf, 0xAu);
v11 = buf[0] - 48;
if(s1[10] != v11 ) return 0;
return 1;
}
int main() {
int name[4];
int i, j, k;
name[3] = (int)'p';
char buf[4];
for(i=97;i<=122;i++) {
for(j=97;j<=122;j++) {
for(k=97;k<=122;k++) {
if(i == (int)'p' || i == j || i == k || j == k || j == (int)'p' || k == (int)'p') continue;
name[0] = i;
name[1] = j;
name[2] = k;
if(ch(name)) {
buf[0] = name[0];
buf[1] = name[1];
buf[2] = name[2];
buf[3] = name[3];
printf("%s\n", buf);
}
}
}
}
return 0;
}
이렇게 간단하게 브포를 할 수 있다.
'write-up > reversing.kr' 카테고리의 다른 글
Replace (0) | 2018.12.19 |
---|---|
ImagePrc (0) | 2018.12.05 |
Easy_CrackMe 풀이 (0) | 2018.12.03 |