[Profiler] Controle de instâncias (Validação de Cliente)

Olá,
Estou trabalhando em um sistema “eficaz” de validação de cliente.
Meu objetivo é que o próprio programa gere um hash de todos as instâncias criadas até então, isso porque se alguma letra se quer do código for modificado, o hash será modificado.(Não me refiro ao object.hashCode() que retorna um hash diferente a cada instância)
Quando o hash tiver sido criado ai é outra história 8) E ainda tenho que repensar isso em relação á reflexão.
Bem, um meio seria alterar a classe Object, porém ainda não sei como fazer isso.(Pois preciso ter certeza que todas as classes carregadas no JVM estão sob “meu controle”).
Já tentei usar meu próprio ClassLoader porém assim eu só teria controle sobre as classes carregadas, o que foge do meu propósito de verificar se o carregamento do programa está regular.
Outra opção que eu vejo é criar um JavaAgent e utilizar as ferramentas da classe Instrumentation, porém isso eu não queria fazer se possível.(Pois não queria ficar dependente do argumento na inicialização)

Alguém tem idéias ? Obrigado :stuck_out_tongue:

Bom dia, pb600.

Pelo que entendi você quer verificar se algum atributo de algum objeto foi modificado durante a execução de um programa Java.
Antes de mais nada, acho você não deve considerar a possibilidade de alterar o Object ou qualquer classe do Java. Seria uma complicação muito grande para um problema que provavelmente pode ser resolvido de forma muito mais simples.

Além disso, vejo duas estratégias principais para atingir seu objetivo:

  1. Alterando suas classes, por exemplo, você pode criar uma interface Inspecionavel e implementá-la em todas as classes que deseja verificar se mudaram. Aí você pode usar seu classloader para armazenar uma lista dos objetos inspecionáveis e recuperar o hash quando necessário. O hash pode ser gerado a partir de uma IDE como o eclipse ou delegado para um método que gere o hash por reflexão, mas a performance e a complexidade podem ser um problema.
  2. Sem alterar as classes, é possível gerar um hash dos atributos através de reflexão. A vantagem é que suas classes permanecem intactas, mas tem o problema citado anteriormente. Além disso, é preciso tomar cuidado para não verificar a própria classe que está verificando as outras.

Se entendi bem o problema, você não precisa se preocupar com todas as instâncias da JVM, por exemplo Strings, datas ou números. Quando você gera um hash para os seus objetos, você já está incluindo os hashes de seus atributos, portanto se qualquer String, data ou número de seus objetos mudar o hash do objeto também muda, logo basta monitorar os seus objetos.

[quote=utluiz]Bom dia, pb600.

Pelo que entendi você quer verificar se algum atributo de algum objeto foi modificado durante a execução de um programa Java.
Antes de mais nada, acho você não deve considerar a possibilidade de alterar o Object ou qualquer classe do Java. Seria uma complicação muito grande para um problema que provavelmente pode ser resolvido de forma muito mais simples.

Além disso, vejo duas estratégias principais para atingir seu objetivo:

  1. Alterando suas classes, por exemplo, você pode criar uma interface Inspecionavel e implementá-la em todas as classes que deseja verificar se mudaram. Aí você pode usar seu classloader para armazenar uma lista dos objetos inspecionáveis e recuperar o hash quando necessário. O hash pode ser gerado a partir de uma IDE como o eclipse ou delegado para um método que gere o hash por reflexão, mas a performance e a complexidade podem ser um problema.
  2. Sem alterar as classes, é possível gerar um hash dos atributos através de reflexão. A vantagem é que suas classes permanecem intactas, mas tem o problema citado anteriormente. Além disso, é preciso tomar cuidado para não verificar a própria classe que está verificando as outras.

Se entendi bem o problema, você não precisa se preocupar com todas as instâncias da JVM, por exemplo Strings, datas ou números. Quando você gera um hash para os seus objetos, você já está incluindo os hashes de seus atributos, portanto se qualquer String, data ou número de seus objetos mudar o hash do objeto também muda, logo basta monitorar os seus objetos.[/quote]
Bom dia, Obrigado pela resposta =D

Como estas tentando me ajudar, irei detalhar mais meu objetivo.

Estou fazendo a validação de um programa para que caso o programa não esteja sendo alterado, ele possa ter acesso ao programa principal. (Ou seja estou desenvolvendo um ‘launcher’ que irá ter acesso remotamente ao arquivo do programa real).
Eu poderia utilizar de encriptação para criar uma chave e retribuir a localização do arquivo real, porém seria muito fácil de descobrir a chave após deobfuscar o launcher, e fazer o processo reverso.

Então pensei em fazer o próprio "launcher" gerar a chave que dá acesso ao programa real, e essa chave seria gerada pela verificação dos códigos do programa, assim a chave só seria a certa caso o programa estivesse exatamente como eu o distribuí.
Porém se eu alterasse cada classe manualmente, nada me garante que a pessoa que está tentando interferir no meu código com outra classe principal afete a validação, pois a classe dele não está sendo monitorada.

Por isso eu precisaria ter acesso completo às instâncias carregadas no programa, pois mesmo que a pessoa tente criar uma alternativa classe principal para interferir na classe original, eu saberia.
O validador pode constar no resultado, portanto não faz mal que a classe que esteja validando verifique a si mesmo, pois assim garanto que o validador não foi alterado para excluir alguma classe :stuck_out_tongue:

Outra coisa, performance não é um grande problema pois isso seria apenas uma validação em tempo de inicialização.
E o hash dos objetos seria gerado por uma nova implementação minha, pois normalmente o hash vem diferente a cada instância, sendo assim impossível de se obter a chave certa.
Sem contar que o hash não pode ser accessível por reflexão de jeito nenhum já que ele supostamente deve ser uma chave secreta :stuck_out_tongue:

Para o objetivo que você demonstrou, acredito que o uso do Java Agent seja uma opção.

Conforme este link, dependendo da implementação da JVM, é possível iniciar o Java Agent durante a execução. Porém, uma opção melhor, dentro do mesmo link, seria usar o MANIFEST.

O problema é que alguém poderia alterar esse MANIFEST. Aí eu acredito que existam opções para evitar isso. Eu já vi jars com assinaturas que verificavam o próprio conteúdo, então se o MANIFEST não estivesse correto ele não funcionaria, mas não sei qual o mecanismo adequado para fazer essas verificações. A documentação sobre assinaturas de MANIFEST está aqui e também tem este outro link interessante.

Uma outra opção, se o público alvo usasse Windows, seria usar um wrapper para executável como o http://launch4j.sourceforge.net/, pois então seria possível passar o argumento do Java Agent para a JVM sem que o mesmo fosse visível para o usuário.

Com o Java Agent em ação e com uma instância da classe Instrumentation, acho que só precisa chamar o método getAllLoadedClasses() para obter a lista de classes.
Um exemplo de implementação simples está neste outro link. A partir disso é só construir a lógica do hash.

Sobre a questão do validador validar a si mesmo, até é possível, desde que ele não tenha atributos que mudam, como listas ou mapas. Como eu havia anteriormente pensado em armazenar a lista de classes observadas numa lista, fiz uma suposição de que o conteúdo dessa lista poderia estar diferente no momento em que a classe verificasse a si mesma, logo ela seria um problema. Bem, ignore essa parte por enquanto.

Eu sei que pode ser chover no molhado, mas toda essa verificação ainda não garante muita coisa. Alguém poderia usar um descompilador (mesmo com código ofuscado), analisar a lógica de validação e usar um editor de bytecode para inibir o método de validação. Eu mesmo já usei essas ferramentas e posso dizer que não é tão impossível para um usuário avançado, basta um tanto de esforço.

Por outro lado, mesmo não sendo especialista em segurança ou em proteção de software, creio que o esforço despendido para inibir usuários mal intencionados será inversamente proporcional à quantidade de “quebras” de segurança, então, ainda que não se possa garantir 100%, cada esforço adicionará uma camada de segurança e tornará o benefício da quebra de segurança menos atraente para um “cracker”.

Olá, sim eu nesse momento estava começando a implementar ^^ mas como disse lá em cima, queria evitar usar agent pois posso acabar piorando a minha situação proporcionando ferramentas que ajudem alguém mal intencionado.
Quando tiver pronto eu colocarei para iniciar agent antes da VM, e sim o launcher distribuído será na verdade um wrapper porém ainda teria o webclient(Applet loader) o que deixa visível os argumentos para os usuários.
E sim estou ciente que não existe meios muito seguros para proteção, mas ainda assim é muito melhor que uma chave encriptada.
Tenho um pouco de experiência com ASM, e estou tentando fazer de uma maneira em que em minha cabeça nem eu consiga passar por cima.

E pensando bem, parar o método de validação é inútil, pois ele é quem gera a chave, e imagine que você adicione uma linha de comando em baixo do resultado do hash para imprimir o hash gerado, ele até irá imprimir, porém o hash será diferente já que a classe foi modificada(checksum) ^^

E provavelmente o usuário não saberá qual é o processo de validação pois minha idéia vai um pouco além :stuck_out_tongue:

Muito obrigado pela atenção e ajuda =D