/* Secret of Mana script dumper 0.1a Problema: Os textos do Secret of Mana estão misturados com códigos que ativam eventos nos jogos, os ponteiros tem que apontar para esses códigos, mas eles não seguem qualquer padrão aparente. Exemplo <$50>Revived Mana Sword!<$40><$02><$16><$0F>h<$28><$10><$51><$02><$00><$00><$00> <$00><$00>The witch Elinee is<$7d> draining people's energy.<$28><$00><$52><$02> <$00> Ai temos 6 ponteiros, como podem ver, não existe nenhuma padrão, código e letras estão misturados e seria muito difícil se locolizar assim. Solução: Trabalalhando com 2 ponteiro podemos calcular a diferença entre o quan- to um ponteiro e o próximo estão distantes. Esse resultado é o tamanho da string que queremos traduzir. Exemplo: 1º ponteiro aponta para: 0x090A9A - Revived Mana Sword<$40><$02><$16><$0F>h<$28> <$10><$51><$02><$00> 2º ponteiro aponta para: 0x090AB8 - <$00> 3º ponteiro aponta para: 0x090AB9 - <$00> 4º ponteiro aponta para: 0x090ABA - <$00> 5º ponteiro aponta para: 0x090ABB - <$00> 6º ponteiro aponta para: 0x090ABC - The witch Elinee is<$7D> draining people's e nergy. Pegando a diferença Entre o Primeiro ponteiro e o Segundo podemos saber até onde essa string realmente precisa ser colocada. Isso deixa mais fácil a visualização e futura edição dos ponteiros. Pensando no futuro: A existencia de [#xxx] poderá ser usada no futuro para manipular os ponteiros, já que basta pegar esse número, multiplicar por 2 e somar ao início do endereço dos ponteiros (nesse caso a OFFSET). Então o algoritmo fica (entre [] significa nome de variável): 1º Dar valor as constantes: Montar array (tabela do jogo) para converter para .txt e o global_counter (conta qual o número da string). 2º Ir até offset [p] e ler o ponteiro. 3º Acrescenta offset em 2 [p+=2] e ir até a posição (próximo ponteiro). 4º Calcular a diferença e formar o tamanho da string [total]. 5º Ler [total] valorers; Se o valor está no array copia a letra para o dump, ca- so contrário copia seus valor no formato <$VALOR>. 6º se [p] menor que 0x0909FD ir para 2º, caso contrário acaba o programa. */ #include #include #define ROM_NAME "som.smc" #define DMP_FILE "dmp.txt" #define OFFSET 0x90216 typedef unsigned char byte; byte read; // byte a ser lido e copiado int size; // tamanho da stream FILE *rom, // arquivo de entrada *dmp; // arquivo com os dados comprimidos int main(){ // Abre os arquivos //****************************************************************************** int primeira_parte, segunda_parte, res1, res2, total, p, temp_p, i, c, global_counter; char tabela[255]; /* primeira_parte = primeiro byte, para formar o ponteiro segunda_parte = segundo byte, para formar o ponteiro res1 = primeiro ponteiro res2 = segundo ponteiro total = tamanho da string p = mainpulação do OFFSET temp_p = endereço do ponteiro i e c = variáveis de trabalho (nomes mais clássicos ever) global_counter = conta o número da string dentro do jogo */ rom=fopen(ROM_NAME, "rb"); // abre arquivo de entrada if(!rom) { printf("Erro ao abrir \"%s\".", ROM_NAME); exit(1); } dmp=fopen(DMP_FILE, "w"); if(!dmp) { printf("Erro ao abrir \"%s\".", DMP_FILE); exit(1); } // Forma array... converte os valores da tabela do jogo para ascii //****************************************************************************** tabela[0x7F] = 0x0A; // LF (quebra de linha ou Line Feed) tabela[0x80] = 0x20; // espaço c = 97; // "a" a "z" for (i=129; i<155; i=i+1) { tabela[i] = c; c++; } c = 65; for (i=155; i<180; i=i+1) // "A" a "Z" { tabela[i] = c; c++; } c = 0x30; for (i=0xB5; i<0xBF; i=i+1) { tabela[i] = c; c++; } // 80 ao BE formados tabela[0xBF] = 0x2E; // . tabela[0xC0] = 0x2C; // , tabela[0xC1] = 0x21; // ! tabela[0xC2] = 0x27; // ' tabela[0xC3] = 0x22; // " tabela[0xC4] = 0x22; // " tabela[0xC5] = 0x3A; // : tabela[0xC6] = 0x2D; // - tabela[0xC7] = 0x2A; // * tabela[0xC8] = 0x21; // ! tabela[0xC9] = 0x26; // & tabela[0xCA] = 0x3F; // ? tabela[0xCB] = 0x28; // ( tabela[0xCC] = 0x29; // ) /* Forma primeiro byte *******************************************************************************/ p = OFFSET; global_counter = 1; do{ fseek(rom, p, SEEK_SET); fread(&read, 1, 1, rom); primeira_parte = read; fread(&read, 1, 1, rom); segunda_parte = read; res1 = (segunda_parte * 0x100) + primeira_parte + 0x200; /* Forma segundo byte *******************************************************************************/ p += 0x2; fseek(rom, p, SEEK_SET); fread(&read, 1, 1, rom); primeira_parte = read; fread(&read, 1, 1, rom); segunda_parte = read; res2 = (segunda_parte * 0x100) + primeira_parte + 0x200; // Forma tamanho da string total = (res2 - res1) - 1; /*Agora temos o tamanho da string [total], iremos ler e identificar o conteúdo da rom [total] vezes. Começando pelo byte indicado pelo [temp_p] a cada byte que leremos (armazenado em [read]) vamos conferir sua existência na talela [tabela[read]] e escrever no texto, caso não esteja na tabela ele é posto em hexadecimal no texto no formato <$NUMERO>. A existência é conferida pelos "if" e a escrita dos não existentes pelos "else". *******************************************************************************/ temp_p = res1 + 0x90000; if (global_counter < 0x100) // Esse if garante que o [#xxx] terá sempre { // três números. fprintf(dmp, "\n[#00%X]\n",global_counter); } else { fprintf(dmp, "\n[#%X]\n",global_counter); } fseek(rom, temp_p, SEEK_SET); do{ fread(&read, 1, 1, rom); if (read >= 0x7F) { if (read < 0xCD) { read = tabela[read]; fwrite(&read, 1, 1, dmp); } else { fprintf(dmp, "<$%X>",read); } //fim do else }// fim do if else { if(read < 0x10) // Esse if garante que o <$xx> terá { // sempre dois números. fprintf(dmp, "<$0%X>",read); } else { fprintf(dmp, "<$%X>",read); } } // fim do else total--; }while(total >= 0); global_counter++; }while(p <= 0x0909FD); //fim do do-while fclose(rom); fclose(dmp); printf("Arquivos abertos e fechados com sucesso! \n"); getch(); exit(0); }