jar-string-editor
v1.0.1
Published
O `jar-string-editor` expoe duas classes principais: `StringSearcher` p a localizaçao de strings e `StringWriter` p a persistencia de modificaçoes
Maintainers
Readme
Uso
O jar-string-editor expoe duas classes principais: StringSearcher p a localizaçao de strings e StringWriter p a persistencia de modificaçoes
1. Buscando Strings em um Arquivo JAR
A classe StringSearcher permite varrer arquivos .class em busca de literais de string. Ela opera de forma assincrona e emite eventos p reportar o progresso e os resultados
const {
StringSearcher
} = require('jar-string-editor');
const JSZip = require('jszip');
const fs = require('node:fs');
async function buscarStringsNoJar(caminhoDoJar) {
// 1. Leia o arquivo JAR como um Buffer
const dadosDoJar = fs.readFileSync(caminhoDoJar);
// 2. Carregue o Buffer em um objeto JSZip
const zip = await JSZip.loadAsync(dadosDoJar);
// 3. Instancie o StringSearcher
const searcher = new StringSearcher();
// 4. Configure os listeners de eventos
searcher.on('read_count', (count) => {
console.log(`[Progresso] ${count} classes lidas...`);
});
searcher.on('finish', (resultados) => {
console.log('\n[Concluído] Busca de strings finalizada. Resultados:');
// Cada item em 'resultados' contém:
// - fileName: o caminho do arquivo .class dentro do JAR
// - classFile: o objeto da classe Java
// - methods: uma lista de metodos com as strings encontradas
resultados.forEach(e => {
console.log(` Arquivo: ${e.fileName}`);
e.methods.forEach(m => {
m.strings.forEach(s => {
console.log(` - String encontrada: '${s.value}' (Indice: ${s.constantIndex})`);
});
});
});
});
// 5. Inicie a busca, passando os arquivos do ZIP
searcher.searchInJar(Object.values(zip.files));
}
// Exemplo de uso:
buscarStringsNoJar('./seu-arquivo.jar');2. Reescrevendo Strings Modificadas em um JAR
Após identificar e modificar os valores das strings (obtidos, p exemplo, atraves do StringSearcher), vc pode utilizar a classe StringWriter p aplicar essas alteraçoes e gerar um novo arquivo JAR
const {
StringWriter
} = require('jar-string-editor');
const JSZip = require('jszip');
const fs = require('node:fs');
async function reescreverStringsNoJar(caminhoDoJarOriginal, caminhoDoJarModificado, modificacoesDeString) {
// 1. Carregue o JAR original
const dadosDoJarOriginal = fs.readFileSync(caminhoDoJarOriginal);
const zipOriginal = await JSZip.loadAsync(dadosDoJarOriginal);
// 2. Utilize o StringWriter p aplicar as modificaçoes
// 'modificacoesDeString' deve ser um array de objetos no formato:
// { fileName: 'caminho/da/Classe.class', constantIndex: 123, value: 'Novo Valor', changed: true }
const novoJarBlob = await StringWriter.write(zipOriginal, modificacoesDeString);
// 3. Converta o Blob resultante p um Buffer e salve o novo JAR
const novoBuffer = Buffer.from(await novoJarBlob.arrayBuffer());
fs.writeFileSync(caminhoDoJarModificado, novoBuffer);
console.log(`\n[Sucesso] Arquivo JAR modificado salvo em: ${caminhoDoJarModificado}`);
}
// Exemplo de uso combinado (assumindo q vc já buscou as strings e tem as modificações):
async function exemploCompleto() {
const caminhoJar = './build/lib/fds-1.0.jar';
const caminhoJarModificado = './build/lib/fds-modificado.jar';
const chaveAntiga = 'um_pequeno_fds';
const novaChave = 'UM_GRANDE_FDS';
const dadosDoJar = fs.readFileSync(caminhoJar);
const zip = await JSZip.loadAsync(dadosDoJar);
const searcher = new StringSearcher();
const modificacoes = [];
searcher.on('finish', async (r) => {
r.forEach((e) => {
e.methods.forEach((m) => {
m.strings.forEach((s) => {
if (s.value === chaveAntiga) {
modificacoes.push({
fileName: e.fileName,
constantIndex: s.constantIndex,
value: novaChave,
changed: true,
});
}
});
});
});
if (modificacoes.length > 0) {
await reescreverStringsNoJar(caminhoJar, caminhoJarModificado, modificacoes);
} else {
console.log('Nenhuma string p modificar encontrada.');
}
});
searcher.searchInJar(Object.values(zip.files));
}
exemploCompleto();