De que se trata o artigo

Este artigo será um estudo dirigido da biblioteca MadShi. Serão mostrados vários aspectos da biblioteca, como as ferramentas de gerenciamento de exceções e API hooking. Os exemplos práticos envolverão a apresentação de um relatório avançado de erros com snapshot automático e informações de debug. O exemplo prático de API hooking mostrará um monitor de arquivos.

Para que serve

A biblioteca MadShi tem vários objetivos, dentre eles Exception Handling e API Hooking. Exception Handling serve para obter informações úteis e concisas sobre erros não tratados. Isso pode ajudar muito a agilizar a correção de bugs e o bug tracking. Além disso, o usuário se sentirá mais seguro com uma mensagem de erro amigável e a possibilidade de enviar um relatório para seu fornecedor. Já API Hooking é essencial para interceptar e modificar funções de DLLs de outros programas ou até do próprio Windows.

Em que situação o tema é útil

Em casos de programas com muitas exceptions não tratadas e muitas mensagens de “Invalid Pointer Operation” e “Access Violation” é importante saber exatamente em que linha e unit o problema se encontra, sem precisar debugar o programa ou levar o Delphi para o cliente. API hooking é útil para integração com outros softwares ou para segurança. É possível impedir o desligamento do servidor, impedir a exclusão ou abertura de arquivos essenciais ao sistema, monitorar tudo o que é digitado (Keylogger), proibir a abertura de certos programas dentre muitas outras utilidades.

Exceções e API Hooking

Com certeza você já se deparou com um erro de Access Violation ou Invalid Pointer Operation durante a demonstração de um sistema feito em Delphi. Essas mensagens, além de feias, são alarmantes para o cliente, e constrangedoras para o desenvolvedor. E por mais que se tente usar logs e tratamentos de exceções mostrando qual a janela aberta e como a exceção foi disparada, no máximo terá o controle que disparou o erro, caso ele tenha sido disparado por um controle. O programador muitas vezes tem que adivinhar em que linha que ocorre o erro ou debugar o programa com uma base de dados real para poder encontrar e corrigir esse bug. Com relação à segurança, utilizando API hooking é possível implementar funções básicas de um sistema de Cyber Café / Lan House sem a necessidade de um software muito caro para isso. Como este artigo é um estudo dirigido será mostrada uma quantidade maior de exemplos teóricos do que sistemas propriamente ditos.

Existem certas bibliotecas para o Delphi tão úteis que deveriam vir com o produto. A política da Borland/Codegear/Embarcadero sempre foi colocar no mercado a ferramenta com os recursos essenciais e permitir que desenvolvedores de componentes e experts desenvolvam extensões para o IDE. Isso é bom para as empresas que desenvolvem componentes, mas não tão bom, talvez, para as empresas que desenvolvem software customizado.

A MadShi Collection é uma coleção de bibliotecas que vem com várias utilidades, dentre elas a MadShiExcept e a MadShiCodeHook. No pacote todo, algumas das suas funcionalidades são gratuitas e com fonte, algumas são gratuitas para uso não comercial e sem fontes, e algumas são apenas de uso por tempo limitado (trial) sem fontes. Mesmo assim a biblioteca inteira pode ser adquirida com fontes e licença para desenvolvedores ilimitados.

É necessário avaliar o custo-benefício. Se uma empresa tem mais de 4 programadores e um número razoável de clientes é possível comprar a MadShiExcept por 449 Euros, para um número ilimitado de programadores e com código fonte.

A biblioteca MadShiCodeHook é um pouco mais cara, podendo chegar a 1999 Euros dependendo da licença. Mas ela permite criar softwares bastante fora do comum, por exemplo interceptando e alterando os parâmetros de chamadas a funções de outros softwares ou da API do Windows.

A grande vantagem de se trabalhar com a MadiShiExcept é a clareza e transparência que ela produz ao exibir erros para o usuário. O usuário sabe que pode enviar para seu fornecedor um relatório de erros para que seja corrigido, e sabe que o relatório desse erro ficou gravado em algum lugar. Nada de tirar print screen da tela, soletrar palavras em inglês técnico, que muitas vezes são incompreensíveis até para quem tem inglês fluente e sem ter que lembrar o que foi feito de errado para o erro ocorrer. Simplesmente é retirado das costas do usuário esse “sentimento de culpa” que pode colocá-lo na defensiva (ou ofensiva) ao se tentar questionar como o erro ocorreu. Ocorreu um erro? A responsabilidade de saber como foi que isso aconteceu é da equipe de desenvolvimento.

Por outro lado a biblioteca MadShiExcept oferece transparência também do lado do desenvolvedor. É possível obter informações completas sobre como o erro foi gerado, inclusive nome da unit e linha onde ocorreu o erro. E ainda é possível mesclar essas informações com outras sobre o ambiente em que o programa estava sendo executado. Armazenando-se essas informações em um banco de dados pode-se ter um sistema de bug tracking unificado para todos os sistemas e clientes.

O primeiro passo é baixar e instalar a biblioteca MadShi. O endereço para download encontra-se na seção de links desse artigo. A Figura 1 mostra as opções que foram instaladas para este artigo.

Figura 1. Instalador da coleção MadShi

Exceptions

Pode-se dividir o conjunto de exceções de um sistema em dois subconjuntos: exceções tratadas, que são aquelas que são esperadas e até desejadas e que por serem conhecidas ocorrem dentro de um try .. except para prover uma mensagem amigável ao usuário e talvez até uma saída alternativa. É comum este try..except estar dentro de um try.. finally maior, para liberar recursos que de outra forma não poderiam ser liberados dentro de um except. A instrução finally sempre é executada, mesmo fechando-se o programa, caso o fluxo esteja dentro de um try, o finally será executado.

O outro grupo de exceções é o grupo das exceções não tratadas, onde a princípio não se sabe como e porque elas ocorrem, e talvez apenas o usuário saiba fazer a “mágica” acontecer, mas não saiba explicar como, e nem deveria, pois na concepção dele está fazendo tudo corretamente.

A Listagem 1 exibe primeiramente uma exceção não tratada e na sequência uma tratada. Na exceção tratada, após o except, o fluxo continua normalmente. Na exceção não tratada o fluxo é interrompido depois do disparo da exceção, e a linha logo abaixo não é executada.

Listagem 1. Exemplo de exceptions tratadas e não tratadas


procedure TfrmDemo.Button1Click(Sender: TObject);
begin
  raise Exception.Create('MissUnderstoodError at adress 0x00000000 :$');
  ShowMessage('Linha logo depois de ter ocorrido a exception.');
end;

procedure TfrmDemo.Button2Click(Sender: TObject);
begin
  try
    raise Exception.Create('MissUnderstoodError at adress 0x00000000 :$');
  except
    on e: Exception do
    begin
      ShowMessage('Ocorreu o seguinte erro: ' + e.Message);
    end;
  end;
  ShowMessage('Linha logo depois de ter ocorrido a exception.');
end;  ... 

Quer ler esse conteúdo completo? Tenha acesso completo