FrostK
게임 | 2026. 7. 18. 23:06

화이트데이1 언팩

작성일: 2019-06-29

url

CODE

/**
* Whiteday nop file Unpacker
* 다솜
* 본 코드를 사용하여 발생된 문제는 사용자에게 있습니다.
**/
//
// Lz77 알고리즘을 알려주신 단풍잎님 감사합니다 ^^
// 기타 나머지는 리버스 엔지니어링으로 알아내었습니다.
//
#include <stdio.h>
#include <string.h>
#include <direct.h>
#include <windows.h>
#include <conio.h>
#define BUFFER_SIZE (1024 * 1024 * 256)
/**
* BIG-SIZE buffer
**/
unsigned char *buff1;
unsigned char *buff2;
/**
* SONNORI Lz77 Xor Key
**/
unsigned short lz77_customkey[] = {
    0xFF21, 0x834F, 0x675F, 0x0034, 0xF237, 0x815F, 0x4765, 0x0233
}; //65313 33615 26463 52 62007 33119 18277 563
//
// NOP file unpack~~~ *^^*
//
void nop_unpack(const char *nopFile)
{
    enum e_noptype {
        NOP_DATA_RAW = 0x00,
        NOP_DATA_LZ77 = 0x01,
        NOP_DATA_DIRECTORY = 0x02,
        NOP_DATA_SONNORI_LZ77 = 0x03
    };
    FILE *fp, *out_fp;
    int off, num, i, j;
    unsigned char key;
    fopen_s(&fp, nopFile, "rb");
    if (!fp)
        return;
    /* the last byte value of NOP file must be 0x12 */
    fseek(fp, -1, SEEK_END);
    if (fgetc(fp) != 0x12) {
        printf_s("* %-15s : 손상된 NOP 파일입니다.\\n", nopFile);
        fclose(fp);
        return;
    }
    /* NOP file header */
    fseek(fp, -9, SEEK_END);
    fread(&off, 4, 1, fp);
    fread(&num, 4, 1, fp);
    printf_s("* %-15s : 총 %d개의 데이터를 포함하고 있습니다.\\n", nopFile, num);
    for (i = 0; i < num; ++i) {
        unsigned char   name[256];
        unsigned char   name_size;
        unsigned char   type;
        int             offset;
        int             encode_size;
        int             decode_size;
        /* File infomation */
        fseek(fp, off, SEEK_SET);
        fread(&name_size, 1, 1, fp);
        fread(&type, 1, 1, fp);
        fread(&offset, 4, 1, fp);
        fread(&encode_size, 4, 1, fp);
        fread(&decode_size, 4, 1, fp);
        fread(name, 1, name_size + 1, fp);
        off += name_size + 15;
        /**
        * [ Data Type ]
        * 0x00 : Raw
        * 0x01 : Lz77 Compressed
        * 0x02 : Directory
        * 0x03 : SONNORI Lz77 Compressed
        **/
        /* In directory, this value used as file path decrypt key */
        if (type == NOP_DATA_DIRECTORY) {
            key = (char)decode_size;
        }
        else {
            decode_size ^= key;
        }
        /* File path decrypt */
        for (j = 0; j < name_size; ++j)
            name[j] ^= key;
        /* we doesn't have enough buffer size. so we skip this file. */
        if (decode_size > BUFFER_SIZE) {
            printf_s(" -> 실패 : %s ? ? ?\\n", name);
            continue;
        }
        /* show current status with percent^^ */
        printf_s("* %0.1f%% : %-68s\\r", ((float)i / (float)num * (float)100.0), name);
        switch (type) {
        case NOP_DATA_RAW:
        {
            fseek(fp, offset, SEEK_SET);
            fread(buff1, 1, encode_size, fp);
            fopen_s(&out_fp, name, "wb");
            if (!out_fp) {
                printf_s(" -> 실패 : %s ? ? ?\\n", name);
                break;
            }
            fwrite(buff1, 1, decode_size, out_fp);
            fclose(out_fp);
            break;
        }
        case NOP_DATA_LZ77:
        {
            int bmask, bcnt = 0, size = 0, off, len;
            unsigned short Lz77Info;
            fseek(fp, offset, SEEK_SET);
            fread(buff1, 1, encode_size, fp);
            /* Lz77 uncompress */
            for (j = 0; j < encode_size; bcnt = (bcnt + 1) & 0x07)
            {
                if (!bcnt) {
                    bmask = buff1[j++];
                } else {
                    bmask >>= 1;
                }
                if (bmask & 0x01) {
                    Lz77Info = *(unsigned short *)&buff1[j], j += 2;
                    off = Lz77Info & 0x0FFF;
                    len = (Lz77Info >> 12) + 2;
                    memcpy(&buff2[size], &buff2[size - off], len);
                    size += len;
                } else {
                    buff2[size++] = buff1[j++];
                }
            }
            if (size != decode_size) {
                printf_s(" -> 실패 : %s ? ? ?%d != %d\\n", name, size, decode_size);
                break;
            }
            fopen_s(&out_fp, name, "wb");
            if (!out_fp) {
                printf_s(" -> 실패 : %s ? ? ?\\n", name);
                break;
            }
            fwrite(buff2, 1, decode_size, out_fp);
            fclose(out_fp);
            break;
        }
        case NOP_DATA_DIRECTORY:
        {
            _mkdir(name);
            break;
        }
        case NOP_DATA_SONNORI_LZ77:
        {
            int bmask, bsrcmask, bcnt = 0, size = 0, off, len;
            unsigned short Lz77Info;
            fseek(fp, offset, SEEK_SET);
            fread(buff1, 1, encode_size, fp);
            /* SONNORI Lz77 uncompress */
            for (j = 0; j < encode_size; bcnt = (bcnt + 1) & 0x07)
            {
                if (!bcnt) {
                    bmask = bsrcmask = buff1[j++];
                    bmask ^= 0xC8;
                }
                else {
                    bmask >>= 1;
                }
                if (bmask & 0x01) {
                    Lz77Info = *(unsigned short *)&buff1[j], j += 2;
                    Lz77Info ^= lz77_customkey[(bsrcmask >> 3) & 0x07];
                    off = Lz77Info & 0x0FFF;
                    len = (Lz77Info >> 12) + 2;
                    memcpy(&buff2[size], &buff2[size - off], len);
                    size += len;
                }
                else {
                    buff2[size++] = buff1[j++];
                }
            }
            if (size != decode_size) {
                printf_s(" -> 실패 : %s ? ? ?%d != %d\\n", name, size, decode_size);
                break;
            }
            fopen_s(&out_fp, name, "wb");
            if (!out_fp) {
                printf_s(" -> 실패 : %s ? ? ?\\n", name);
                break;
            }
            fwrite(buff2, 1, decode_size, out_fp);
            fclose(out_fp);
            break;
        }
        default: // unknown type
            printf_s(" -> 실패 : %s ? ? ?\\n", name);
            break;
        }
    }
    fclose(fp);
    return;
}

int main(int argc, char *argv[])
{
    /* 콘솔 속성 변경 */
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
    /* 인트로 표시 */
    SetConsoleTitle("NOPUnpack - http://c...content-available-to-author-only...r.com/wdlabyrinth");
    printf_s("o------------------------------------------------------------------------------o");
    printf_s("| W h i t e D a y :: A Labyrinth named school ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?|");
    printf_s("o------------------------------------------------------------------------------o");
    printf_s(" 네이버 카페 [화이트데이 게임 - 미궁의 열쇠] http://c...content-available-to-author-only...r.com/wdlabyrinth\\n");
    printf_s(" 제작자: 다솜(Naver ID - love947345, MSN - eunju...@hotmail.com)\\n");
    printf_s("o------------------------------------------------------------------------------o");
    printf_s(" NOP파일을 풀어줍니다..^^\\n");
    printf_s(" 화이트데이가 설치된 폴더에서 실행하시면, 게임실행에 문제가 생길 수 있습니다.\\n");
    printf_s(" 계속 하실려면 아무키나 누르세요.\\n");
    printf_s("o------------------------------------------------------------------------------o");
    _getch();
    /* 버퍼 메모리 할당 */
    if (!(buff1 = (unsigned char *)malloc(BUFFER_SIZE)) || !(buff2 = (unsigned char *)malloc(BUFFER_SIZE))) {
        printf_s("* 메모리 할당에 실패하였습니다.\\n");
        getchar();
        return 0;
    }
    char path[256];
    int i;
    /* 데모버전 NOP 파일 */
    nop_unpack("whiteday.nop");
    /* 데모버전 NOP 패치 파일 */
    for (i = 100; i < 999; ++i) {
        sprintf_s(path, sizeof(path), "patch%02d.nop", i);
        nop_unpack(path);
    }
    /* 정식버전 NOP 패치 파일 */
    for (i = 100; i < 999; ++i) {
        sprintf_s(path, sizeof(path), "whiteday%03d.nop", i);
        nop_unpack(path);
    }
    /* 오!재미 NOP 파일*/
    for (i = 99; i < 999; ++i) {
        sprintf_s(path, sizeof(path), "mod_beanbag%03d.nop", i);
        nop_unpack(path);
    }
    /* 메모리 해제 */
    free(buff2);
    free(buff1);
    printf_s("o------------------------------------------------------------------------------o");
    printf_s(" 모든 작업이 끝났습니다. 종료하실려면 엔터키를 누르세요.\\n");
    getchar();
    return 0;
}

MAP


MODEL

IMAGE

HL1

HL2

'게임' 카테고리의 다른 글

붉은보석 기억용  (0) 2026.07.18
데카론  (0) 2026.07.18
포탈1 멀티  (0) 2026.07.18
Sudden Attack Full Source + Dev Tools  (0) 2026.07.18
FrostK

FrostK

Writer

개인 사이트 버리고 이곳으로 이주함