Possibilidade de "find and replace" uma lista de hexadecimais

Iniciado por Snow, Outubro 02, 2018, 11:29:51 AM

tópico anterior - próximo tópico

0 Membros e 1 Visitante estão vendo este tópico.

Snow

Olá pessoal, estou precisando de ajuda com uma situação que me apareceu durante minha caminhada, procurei e testei vários editores hexadecimais, mas não consegui algo que realizasse o seguinte:
-Tenho vários Hexadecimais originais fora de sequência.
ex:
Lista original, na ROM:

WWWWWWWW B1B2B3B4 C1C2C3C4 D1D2D3D4
E1A2A3A4 F1B2B3B4 XXXXXXXX YYYYYYYY
A1A2A3A4 ZZZZZZZZ C1C2C3C4 D1D2D3D4

Obs: o tamanho é o mesmo para cada um dos que serão substituídos.

Quero substituir os que estão em negrito por uma outra sequência de Hexadecimais, fincando por exemplo:
AAAAAAAA B1B2B3B4 C1C2C3C4 D1D2D3D4
E1A2A3A4 F1B2B3B4 CCCCCCCC FFFFFFFF
A1A2A3A4 CCCCCCCCC1C2C3C4 D1D2D3D4

Estou fazendo manualmente, pois os editores que testei, substitui uma única sequência por vez.
O que preciso é: um editor que pegue a lista a procurar e substitua pela outra lista.
Procurar por:
WWWWWWWW
XXXXXXXX
YYYYYYYY
ZZZZZZZZ
Substituir em sequência por:
AAAAAAAA
CCCCCCCC
FFFFFFFF
CCCCCCCC

Se alguém conhecer algum programa que faça essa tarefa, ou alguma maneira de se conseguir isso.

denim

Eu não conheço, e acho difícil encontrar um programa que faça algo tão específico...

Snow

Então denim... eu imaginei que pudesse ter, por que nada mais é do que ao invés de procurar e substituir por um valor.... seria uma cadeia de valores... Sou leigo em programação, to estudando o código C de um programa de Inserção e recalculo de ponteiros para ver se consigo adaptar...

tvtoon

Existem várias considerações sobre o assunto...

1) É uma lista fixa de valores repetidos assim, em larga escala?

2) Você sabe o escopo desses valores a serem substituídos? O objetivo é saber se há uma repetição após esse trecho lógico a ser substituído.

3) Você tem certeza que essa lista não pode ser obtida na imagem binária, via ponteiros no mínimo?

4) Finalmente, qüal a finalidade dessa substituição? Textos, gráficos etc...

Kamppello

Se não me engano o Hex Editor Neo faz isso, entretanto ele não carrega tabelas.

Snow

tvtoon, considerações importantes as suas:

1) Os valores são ponteiros originais, quero substituir por ponteiros modificados.

2) Os ponteiros não estão todos em sequência, não consigo usar o Kruptar por exemplo, estudei muito ele, mas quando vai para o ponteiro que está fora de ordem, acaba dando problema.

3) Eles são os ponteiros, consegui de uma forma alternativa alterá-los automaticamente usando um Dump de texto pra marcar os offsets dos finais de cena e importando pro Excel. Maneira meio que alternativa, mas é com o que sei trabalhar.... então com alguns cliques consigo pegar os ponteiros originais numa coluna e na seguinte tenho eles recalculados.

4) Substituição de ponteiros antigos, por novos. Esses ponteiros não seguem uma sequência no bloco.

Então a ideia era com Editor Hex fazer a substituição no arquivo do jogo.

Buscar: pont1, pont2, pont3, pont4 (a lista q tenho de valores hexadecimais distintos na coluna do excel)
Subistituir por: pont1_recalculado, pont2_recalculado, pont3_recalculado...

acabei de fazer 80!!! um por um!

Kamppelo,
Com certeza irei testá-lo agora.

kuroi

Bom dia, cara!
Então... Quando me deparei com esse tipo de problema, eu fui "obrigado" a inserir no arquivo de Dump os valores encontrados referentes aos endereços dos ponteiros originais no cabeçalho de cada script dumpado. Por exemplo:

{000A35D8}
O homem veio da galinha,{0A}
mas a galinha nega{0A}
paternidade.{00}

Depois, na hora de reinserir você obtem o valor do ponteiro novo baseado na posição atual que você estiver no arquivo binário de saída, alocando-o em uma variável chamada "ponteiro_novo" e captura o endereço do ponteiro original (que está impresso no Dump) em uma variável chamada "ponteiro_orig".

Com os dois em mãos, crie uma função (ou método, dependendo da linguagem) que faz o cálculo do ponteiro passando por parâmetro o ponteiro_orig e o ponteiro_novo. Aí dentro da função você grava o ponteiro_novo na posição em que estava o ponteiro_orig.

Simples assim! Rsrsrs

Se tiver mais dúvidas, eu irei procurar o código que eu tenho em C aqui sobre esse algoritmo pra explicar melhor...

Até mais!!
君の夢が叶うのは誰かの影じゃないぜ。
風の強い日を選んで走ってきた。

Snow

#7
kuroi, boa tarde, vlw a atenção.. o que acontece é que tenho uma noção básica de Linguagem C somente... estou lendo exatamente o seu livro sobre Romhacking (que é muito bem explicado, acho que todos que têm interesse em criar ferramentas para romhacking deveriam ler) para compreender como faz a leitura e a escrita no arquivo binário sem ter problemas.

A ideia que tive foi exatamente como você mencionou, agora falta transferir isso pra linguagem C.

Eu consegui isso:
{000A35D8}
O homem veio da galinha,{0A}
mas a galinha nega{0A}
paternidade.{00}


mas de uma maneira alternativa, usando um Extrator gringo, e a partir daí, usando o Excel (o qual domino bem) eu consigo a lista de ponteiros Originais e a Lista de ponteiros Modificados de forma automática, assim pelo menos eu só tenho que fazer o "replace".

Então o que eu to pensando basicamente é um programa simples pra fazer o seguinte:

1.
Ler arquivo original (para percorrer no intervalo de texto)
Ler o arquivo traduzido (para percorrer no intervalo de texto)

2.Achei a quebra de cena, no próximo byte pego o offset pra fazer o cálculo do ponteiro. Faço isso nos dois arquivos, assim vou armazenar os dois ponteiros (original e o novo).

3. Busco no arquivo modificado o ponteiro original, substituo pelo ponteiro novo..

Acredito ser essa lógica... 


kuroi


void Dumper(){

FILE *arquivo, *arquivo_saida;
unsigned int Offset_inicio, Offset_fim;
unsigned int OffsetInicioPonteiros = 0x00;//Inicio do arquivo
unsigned int OffsetFimPonteiros = 0xFFFFF;//Fim do arquivo
unsigned int Byte1, Byte2, Byte3, Byte4;

//Abre o arquivo de leitura       
arquivo = fopen("seujogo.bin", "rb");

//Inicia o ponteiro do arquivo no comeÁo
fseek (arquivo, OFFSET, SEEK_SET);

//Aloca em memÛria um unsigned char de tamanho 2097152 em decimal
memoria = (unsigned char*) malloc (sizeof(unsigned char)*TAM_ARQ);

//Le o arquivo de entrada e grava todos os seus bytes na memÛria, retornando um contador, ou seja, dando um Malloc na bagaÁa
cont = fread (memoria, sizeof(unsigned char), TAM_ARQ, arquivo);

//Depois que toda a rom estiver na memoria, o arquivo È fechado
fclose(arquivo);

//Inicio do loop que ira ler cada byte do arquivo
for(i=Offset_inicio;i<=Offset_fim;i++){
       
//Primeiro dialogo
    if(i == Offset_inicio){

//Quebra o endereço atual em quatro Bytes
Byte4 = (unsigned char)(i & 0x000000FF);
Byte3 = (unsigned char)((i>>8) & 0x000000FF);
Byte2 = (unsigned char)((i>>16) & 0x000000FF);
Byte1 = (unsigned char)((i>>24) & 0x000000FF);

//Verifica se os quatro Bytes foram encontrados em sequencia dentro de todo o arquivo binário
for(j=OffsetInicioPonteiros;j<=OffsetFimPonteiros;j++){

if((Byte1 == memoria[j]) && (Byte2 == memoria[j+1]) && (Byte3 == memoria[j+2]) && (Byte4 == memoria[j+3])){
//Se encontrar, gravar o endereço dele no arquivo de saída (no header do script)
fprintf(arquivo_saida, "{%.8x}\n", j);
break;
}
}
}
//Segundo dialogo (Faz a mesma coisa, porém do segundo diálogo em diante)
if(memoria[i-1] == 0x00){
Byte4 = (unsigned char)(i & 0x000000FF);
Byte3 = (unsigned char)((i>>8) & 0x000000FF);
Byte2 = (unsigned char)((i>>16) & 0x000000FF);
Byte1 = (unsigned char)((i>>24) & 0x000000FF);

for(j=OffsetInicioPonteiros;j<=OffsetFimPonteiros;j++){

if((Byte1 == memoria[j]) && (Byte2 == memoria[j+1]) && (Byte3 == memoria[j+2]) && (Byte4 == memoria[j+3])){

fprintf(arquivo_saida, "{%.8x}\n", j);
break;
}
}
}

//Continuar o Dumper...
}
}

//Trecho do inserter que faz a parte da troca dos ponteiros
void Inserter(){

//Loop que ira ler cada linha do arquivo de texto
while (fgets(s, 100, arq) != NULL){

//Ignorar os separadores de script
if(!strcmp(s, "----------------\n") || !strcmp(s, "----------------")){
continue;
}

//Ler o arquivo de texto Byte por Byte
for(i=0;i<(int)strlen(s)-1;i++){

//Verificar se foi encontrado uma abertura de chaves
if(s[i] == '{'){

//Verificar se foi encontrado um fechamento de chaves depois do terceiro caractere
if(s[i+3] == '}'){

//Gravar o Hexadecimal de dentro das chaves
sscanf(&s[i+1], "%XX", &c);
fputc(c,out);

//Verificar se o Byte lido no arquivo de texto (Dump) é uma quebra de linha
if(c == 0x00 && s[i+4] == 0x0A){

//Se for uma quebra de linha, usar a função ftell() para retornar a posição atual do arquivo binário e alocá-la na variável ponteiro_mod. Esse será o valor do novo ponteiro.
ponteiro_mod = ftell(out);
}

//Somar mais 3 no iterador para continuar no Byte seguinte
i= i+3;
}

//Ao encontrar um ponteiro no header do script
if(s[i+9] == '}'){

//Alocar o ponteiro na variável ponteiro_orig
sscanf(&s[i+1], "%X", &ponteiro_orig);

//E chamar a função calcula_ponteiro() passando por parametro o nome do arquivo binário, o ponteiro_orig e o ponteiro_mod
calcula_ponteiro(nome, ponteiro_orig, ponteiro_mod);

//Somar mais 9 posições no iterador
i=i+9;
}
}
else{

//Se não houver nenhum ponteiro ou Byte de controle mais para ler, gravar os caracteres encontrados no arquivo de texto dentro do binário
c = s[i];
                fputc (cont, out);
}
}
}

void calcula_ponteiro(char* arquivo_mod, unsigned int ponteiro, unsigned int ponteiro_mod){

FILE *arquivo;
unsigned int Byte1, Byte2, Byte3, Byte4;

//Proteger para que não entrem ponteiros zerados na função
if(ponteiro != 0x00 && ponteiro_mod != 0x00){

//Abrir o arquivo binário para leitura e escrita
arquivo = fopen(arquivo_mod, "r+b");

//Separar os Bytes do ponteiro_mod
Byte1 = (unsigned char)(ponteiro_mod & 0x000000FF);
    Byte2 = (unsigned char)((ponteiro_mod>>8) & 0x000000FF);
    Byte3 = (unsigned char)((ponteiro_mod>>16) & 0x000000FF);
    Byte4 = (unsigned char)((ponteiro_mod>>24) & 0x000000FF);

//Seguir até a posição binária do endereço do ponteiro original
fseek (arquivo, OFFSET+ponteiro, SEEK_SET);

//Gravar os quatro Bytes separados anteriormente na posição do ponteiro original
    fwrite(&Byte4, sizeof(unsigned char), 1, arquivo);
  fwrite(&Byte3, sizeof(unsigned char), 1, arquivo);
    fwrite(&Byte2, sizeof(unsigned char), 1, arquivo);   
    fwrite(&Byte1, sizeof(unsigned char), 1, arquivo);

//Fechamento do arquivo binário
    fclose(arquivo);
}
}


Acho que é isso... Dá uma estudada aí e adapta pras suas necessidades.

Até mais!!
君の夢が叶うのは誰かの影じゃないぜ。
風の強い日を選んで走ってきた。

tvtoon

Vou só acrescentar que você pode usar o utilitário Atlas para esses casos problemáticos, mas é o mesmo que aprender programação, logo a escolha fica clara.

Snow

kuroi, excelente, consegui uma direção estou estudando o funcionamento dessas funções e da lógica usada. Ajudou imensamente..

tvtoon imagino que a resposta é aprender a programar rsrs.. de qualquer forma olharei ele pra ver como funciona...

obrigado pessoal, quando eu conseguir eu dou um retorno..

Snow

Voltei pra dar um retorno aos colegas que puderam ajudar, estou muito grato..

Eu não mexia com programação tinha uns 10 anos, desde o curso de informática.... suei! mas é incrível como se aprende quando se tem que fazer algo em que realmente está interessado.

kuroiSeu código foi o norte que me faltava, tive que pesquisar manipulação de arquivos, as funções, deslocamento de bits...finalmente depois de fazer testes e ir arrumando a ferramenta saiu...o que eu gastava quase uma hora pra fazer, agora bastam alguns segundos.

A propósito, a única coisa que não compreendi bem como funciona é a parte de deslocamento de bits que você fez:

                        Byte4 = (unsigned char)(i & 0x000000FF);
         Byte3 = (unsigned char)((i>>8) & 0x000000FF);
         Byte2 = (unsigned char)((i>>16) & 0x000000FF);
         Byte1 = (unsigned char)((i>>24) & 0x000000FF);
Deu certinho, mas fiquei sem compreender bem o significado..



tvtoon

Isso serve para separar os valores de um tipo inteiro (4 bytes) em unidades de bytes. É uma "máscara", como é conhecida.

Se for usar assim, é recomendável misturar no laço próximo: shift por 8 vezes i.

kuroi

Eai, cara!
Então... Esse conteúdo eu explico em detalhes no meu manual da página 99 até a página 109...

Qualquer dúvida é só me perguntar aqui!

Até mais!!
君の夢が叶うのは誰かの影じゃないぜ。
風の強い日を選んで走ってきた。