[CODEGATE 2014] 코드게이트 2014 Clone Technique Writeup



 □ description

==========================================

Limited processes will be generated. 

Which one has the flag?


http://58.229.183.26/files/clone_technique.exe_b9b0870fb1b877cecf5ea2ae615e12eb

==========================================


개인적으로 윈도우 리버싱 문제를 상당히 좋아하는 편인데 

이 문제는 나를 멘붕 시키기에 충분했다.


400개의 프로세스가 무한대로 생성되는데 여기서 한 개라도 비정상종료(사용자에 의해) 된다면 또 다시 무한대로 생성되는(?) 듯 했다. 즉 자식의 자식의 자식의 자식의 자식 프로세스 인듯...

WriteProcessMemory 로 자기자신의 프로세스에 무언가 연산을 거친 값을 Write 한다.

(멘붕에 의해 잘못된 분석일수도 있습니다 일침 가해주세요)


여러가지 꼼수를 이용해서 풀 수 있겠지만 (코드패치 or memory dump) 대회 당시에 딱히 생각이 나지 않아서 Key Verify 루틴을 코딩하여 풀이했다.



눈여겨 볼 함수는 sub_401070 이다. ROL,ROR 을 통해 인자로 들어온 값을 verify 한다.


그 뒤 return 값을 가지고 XOR 을 거쳐서 자기자신의 프로세스의 임의 영역에 Write 한다.



분석은 여기까지 했는데 문제의 참신성에 비해 암호화 루틴이 간결한 편이었다.




char *str=(\x0F,\x8E,\x9E,\x39,\x3D,\x5E,\x3F,\xA8,

                 \x7A,\x68,\x0C,\x3D,\x8B,\xAD,\xC5,\xD0,

                 \x7B,\x09,\x34,\xB6,\xA3,\xA0,\x3E,\x67,\x5D,\xD6");


inline int ROL(int a,int b){

    return (a<<b)|((unsigned)a>>(32-b));

}


char* verify(char *a1,int a2,int a3){

    int i;

    int len;

    char *v8;


    len = strlen(a1);

    v8 = (char*)malloc(len+1);

    memset(v8,0,len);

    for(i = 0;i < (len - 1);i += 2)

    {

        v8[i] = a2 ^ a1[i];

        a2 = ROL(a2,5)^0x2f;

        if(!a1[i + 1]){

            break;

        }

        v8[i + 1] = a3 ^ a1[i + 1];

        a3 = ((unsigned char)a2)^ROL(a3,11);

    }


    return v8;

}


inline int cast(int a,int b)

{

    if(b==0)

    {

     return 1;

    }

    int d = cast(a,b/2);

    if(b%2)

   {

        return d*d*a;

    }

   else

   {

        return d*d;

    }

}


int gen(int a1,int a2,int ct){

    printf("Key : %s\n",verify(str,a1,a2));

    a1^=0xB72AF098u;

    a2 = (a1*a2)^a2;

    int v1 = a1+7*cast(a1,2)*29;

    int v6 = cast(v1^a2,((unsigned)v1%2)+5);

    if((unsigned int)a1<=0xD0000000u)

    {

        int ret;

        do{

            if(ct>400) return 0;

            ct++;

            ret = gen(v1,v6,ct);

            v1 = ret;

            v6 = cast(ret^v6,ret%30);

        }while(ret);

        return 0;

    }

  else

  {

        return (13*((unsigned)v1/27))^0x1f2a990d;

    }

}


int main()

{

    gen(0xA8276BFA,0x92F837ED,1);

    return 0;

}





외계어들 중에 유일하게 읽을 수 있는 키가 존재한다


KEY : And Now His Watch is Ended


저작자 표시
신고

 

티스토리 툴바