Ajuda com ASM

24 respostas
Jedi_FeniX

Estou querendo usar o ASM para poder ler uma classe já compilada, mas não estou conseguindo nem sair do “Hello World” :? , alguém poderia ajudar?

24 Respostas

Marky.Vasconcelos

Cara… tem muita coisa pra voce aprender como resposta para a pergunta “poderiam me ajudar?”.

Seja mais especifico.

Jedi_FeniX

Como começar no ASM? Você teria algum tutorial bem básico? Por exemplo de como ler um código a partir de um .class?
Tentei usar o javassist para fazer isso, mas acho que com ele não dá.

T

Acho que é melhor começar pelo FAQ - ele indica que é bom você rodar o ASMifier pelo menos para entender o que o ASM requer, e é interessante você ver a saída do programa.

http://asm.ow2.org/doc/faq.html

Marky.Vasconcelos

Também existe um plugin pro eclipse que facilita usar o ASMifier.

E qual sua intenção em usar ASM?

Quer ver o código fonte ou como funciona os .class?

T

Atenção: o ASM não é adequado para você "descompilar" um programa. Ele é muito bom, por exemplo, para você criar ou modificar uma classe (alguns frameworks de AOP usam o ASM, se não me engano).

Se você quer simplesmente "desassemblar" um programa (ou seja, .class -> bytecodes), use o javap mesmo.

O que você quer fazer com o ASM?

Jedi_FeniX

Eu quero alterar partes do código. Por exemplo pegar a linha de um determinado método e comentar a mesma e ai incluir uma outra linha.
E também queria saber se eu posso procurar dentro do código por uma determinada palavra. Por exemplo se find(test.a()).

Marky.Vasconcelos

entao… use o ASMifier comparando a classe compilada e a classe que voce quer como resultado.

Ele vai te mostrar o código necessario para alterar.

T

Jedi_FeniX:
Eu quero alterar partes do código. Por exemplo pegar a linha de um determinado método e comentar a mesma e ai incluir uma outra linha.
E também queria saber se eu posso procurar dentro do código por uma determinada palavra. Por exemplo se find(test.a()).

Pegar uma linha e comentar, e incluir outra linha? O ASM não é indicado para isso (já que trabalha com .class, não com .java). O correto, no seu caso, é trabalhar com alguma API de “Abstract Syntax Tree”, tais como as que o Eclipse e o NetBeans usam para analisar e compilar programas.

Jedi_FeniX

Teria alguma API para indicar thingol?
Lembrando que eu só tenho os .class.

T

Se você só tem o .class aí fica um pouco mais difícil, já que você só tem os bytecodes.

Você não tem em bytecodes o conceito de “editar ou comentar uma linha”, que é coisa de código java, não de bytecodes.

Talvez, dependendo do que você quer, você tenha de descompilar o código, arrumar o código descompilado manualmente, e então recompilar.

T

O que você poderia fazer com o ASM é uma ferramenta que pegaria um .class e produziria outro .class, mas com constantes strings modificadas (por exemplo). Digamos que o .class original tivesse uma string assim:

public static final String AUTOR = "José Aparecido";

você poderia fazer algo que gerasse um .class com algo semelhante a:

public static final String AUTOR = "Maria das Dores";
T

O que não dá para fazer em ASM de forma muito trivial é algo assim:

// Original
for (int i = 1; i <= 10; ++i) {
    System.out.println (i);
}
// Alterado
while (i < 100) {
    System.out.printf ("%d\n", i++); 
}

Que tipo de modificação você quer fazer? Diga que talvez a gente consiga indicar uma solução.

Jedi_FeniX

É só tenho os .class.
Estava tendo fazer isso com o javassist, nele eu consigo alterar o bytecode, mas só incluir código, não consigo apagar nada.
Abaixo tem um exemplo para vocês entenderem melhor:

Exemplo:

Um usuário faz um upload para myApp.
E ai myApp abre o . jar, lê o .class e faz as alterações necessárias no .class.

T

Quais são as “alterações necessárias”?

Jedi_FeniX

A alteração que quero fazer é deste tipo.

A minha aplicação abre o .class e modifica a chamada de um método.

Original:

if(a.equals(b)){ b.methodA(); }

Modificado:

if(a.equals(b)){ b.methodB(); }

T

Só isso? Se o método tiver exatamente a mesma assinatura, então você só precisa implementar visitMethodInsn; você troca a chamada a methodA por uma chamada a methodB.

Se tiver assinatura diferente (por exemplo, um parâmetro a mais), então é mais complicado porque você precisa remover ou adicionar código, e isso não é trivial.

Jedi_FeniX

Bom, como o meu tempo é pequeno tem como “fazer” a assinatura do método ser a mesma para que fique mais fácil.
Você teria algum exemplo de como eu posso fazer esta modificação? E outra coisa eu teria que varrer o .class inteiro atrás do methodA().

T

Você entendeu como é que se usa o ASM?
Ele usa o pattern “visitor”.
Então você carrega o .class com o ASM e então o ASM chama uma classe que você define; para cada classe de bytecodes (como invokespecial, invokevirtual etc.) existe um método determinado, que você pode sobrecarregar ou não.
Sobrecarregar esse método é definir o que fazer quando você encontrar a tal instrução.
No seu caso, para todas as instruções, exceto visitMethodInsn, você simplesmente deixa a instrução do jeito que está. Mas visitMethodInsn deve mudar a chamada de methodA para methodB.

Jedi_FeniX

Aí que está eu ainda não entendi muito bem, fui no site do ASM, mas achei complicada a explicação deles.
Você teria algum outro material para indicar? Baixei do site do ASM alguns exemplos, mas mesmo assim está difícil de entender.
Gostaria de agradecer a ajuda que vc está dando!!! Valeu!!! :thumbup:

T

Use o javassist então; o ASM é reconhecidamente difícil de usar; se estiver com pressa não é a ferramenta mais indicada para usar.

Jedi_FeniX

O javassist perto do ASM é uma “Mãe”, muito fácil de usar.
O problema que com ele eu não consigo fazer essa funcionalidade, percorrer um bytecode atrás de um método e mudar o método.
Você sabe se tem como percorrer um bytecode com javassist? Por exemplo, pego um .class entro no methodA e vejo o que tem no escopo do método, depois entro no methodB vejo o que tem no escopo do método, faço a alteração e depois vou para ooutro método e etc…

T

redirectMethodCall

Jedi_FeniX

Cara valeu pela ajuda este método me ajudou muito!!!
Só que cai em uma situação bem chata.
Aonde eu tenho que trocar uma objeto que chama um metodo por uma chamada de um objeto com método static.
Por exemplo:

Original:

objecA.methodA()

Modificado:

ObjectB.methodC()

Tentei usar os métodos da classe CodeConverter que você passou na outra solução, mas não tive muito sucesso.

T

NO seu caso, provavelmente você terá de usar outra classe ( javassist.expr.MethodCall ) - http://www.csg.is.titech.ac.jp/~chiba/javassist/html/javassist/expr/MethodCall.html - e você terá de dar uma olhada no método replace.
Veja: http://www.csg.is.titech.ac.jp/~chiba/javassist/tutorial/tutorial2.html

DISCLAIMER - nem baixei o Javassist e nem cheguei a mexer com ele; tudo que estou lhe afirmando é resultado de ler a documentação. Espero que “replace” ajude, mas não posso garantir o resultado.

Criado 26 de maio de 2009
Ultima resposta 27 de mai. de 2009
Respostas 24
Participantes 3