Desenvolvimento - Delphi
Proteção contra Pirataria - Utilizando hardlocks
Aprenda a proteger seus programas utilizando soluções profissionais de proteção por chave de hardware.
por Victory FernandesRecentemente, entrei em contato com os principais fabricantes de hardlock disponíveis no mercado, desmonstrando meu interesse em avaliar seus produtos e publicar um artigo sobre os mesmos. Obtive total apoio por parte da PROTEQ que me encaminhou gratuitamente um kit completo de desenvolvimento, contendo dois dos seus modelos de chaves: chave para porta paralela e USB.
Neste artigo, abordaremos a problemática da pirataria, a solução PROTEQ e as conclusões sobre o produto.
Tipos de Proteção
Creio que os leitores já conhecem e aplicam diversas formas de proteção de seus produtos por recursos de software, tais como:
- Gerar arquivos em algum lugar do disco que contenha informações para correta abertura de seus programas.
- Gerar chaves no Regedit do Windows.
- Verificar números disversos como: número de HD, Bios, MAC da placa de rede e etc
Quando falamos em proteção, é muito importante lembrar que não existe proteção 100% segura; caso contrário, o problema da pirataria mundial não seria tão preocupante.
No entanto, no momento de definir qual tipo e nível de proteção queremos para nossos aplicativos, devemos levar em consideração a relação custo-benefício da abordagem escolhida.
Assim, podemos verificar que despendendo um grande tempo na implementação de uma solução complicada de proteção como as descritas acima, teremos um alto custo e um benefício, no mínimo, duvidoso.
As soluções de proteção por chave de hardware por sua vez, apresentam um baixo custo de implementação, devido a programas como o Envelopador - PROTEQ, e um alto benefício quando considerado o nível de proteção obtido.
A Solução PROTEQ
Dentre outros produtos, a PROTEQ oferece as chaves COMPACT, nas versões COMPACT-500 e COMPACT-Net (local e rede respectivamente), com 512 bytes de memória programável, e funções de leitura escrita, encriptação e contadores. Voltado para empresas desenvolvedoras de software cada produtor de software personaliza seu plugue, de forma que apenas os clientes que o possuirem podem utilizar seu software
Para acessar a chave, utilizamos um software formatador que dentre outras funções permite configuração e acesso à memória da chave.
Figura 1. Tela de opções do programa formatador.
Uma das opções que mais me chamou atenção no produto, opção esta que não me lembro de ter encontrado em outras marcas de hardlock, foi a facilidade na hora de proteger um determinado arquivo com o programa chamado Envelopador.
Fiquei surpreso ao constatar que não é necessário conhecer nenhum comando de leitura ou escrita da chave para proteger um arquivo qualquer, bastando apenas selecionar o arquivo e aplicar as opções desejadas. O programa Envelopador então faz todo o trabalho de adicionar ao arquivo escolhido as chamadas de verificação da presença da chave.
Vale ressaltar que com ele podemos proteger qualquer tipo de arquivo, inclusive .exe para os quais eu não possuimos os fontes.
Figura 2. Tela de opções do programa envelopador.
Comunicando com a Chave via Delphi
No momento de comunicar com a chave via um projeto em Delphi, devo admitir que senti uma certa dificuldade, uma vez que o demo disponibilizado implementa as funções disponíveis de forma bem elementar e pouco generalizada; por isso decidi implementar um demo mais completo que espero, venha a ser distribuído em conjunto com o produto.
Figura 3. Demo com todas as opções disponíveis implementadas.
O demo desenvolvido implementa todas as funções de leitura e escrita disponíveis, de forma generalizada, com completo tratamento de erro e totalmente comentado. Ele também separa toda a parte de comunicação com a chave numa unit a parte, a unit Proteq_Funcoes.pas, de forma que o leitor que deseje utilizar o produto, só presisa adicionar a referida unit ao seu projeto e chamar as funções por ela disponibilizada.
A unit Proteq_Funcoes.pas implementa as seguintes funções:
Function C500(Comando : pchar):Integer stdcall; external "c50032.dll" name "C500"; Function Trata_Erro(retorno: Integer): String; Function Inicia_Proteq(senha: String; var codigo_interno: String): Boolean; Function Libera_Licenca(senha: String): Boolean; Function Finaliza_Proteq: Boolean; Function Encriptar(var valor: String): Boolean; Function Desencriptar(var valor: String): Boolean; Function Ler_Memoria(var valor: String; inicio, tamanho: Integer; desencripta: Boolean): Boolean; overload; Function Ler_Memoria(var valor: String; desencripta: Boolean): Boolean; overload; Function Grava_Memoria(valor: String; inicio: Integer; encripta: Boolean): Boolean; overload; Function Grava_Memoria(valor: String; encripta: Boolean): Boolean; overload; Function Ler_Contador(var valor: String): Boolean; Function Decrementar_Contador(valor: String): Boolean;
Nela as funções de leitura e escrita da memória da chave são generalizadas, de forma que podemos ler qualquer parte da memória indicando o byte de início e fim do procedimento, e uma variável Boolean para indicar se o valor lido deve ser desencriptado ou se o valor a ser escrito deve ser encriptado.
Há ainda funções para verificação de chave, liberação de licença de acesso via rede, leitura e decremento de contador de execuções.
Meu primeiro programa protegido
Veremos agora como é fácil usar a unit Proteq_Funcoes.pas para criar nosso primeiro programa protegido em Delphi, que verifica periodicamente a presença de uma chave específica.
Em um novo projeto do Delphi, clique no Menu>Project>Add to Project... e selecione a unit Proteq_Funcoes.pas. Com o formulário selecionado clique no Menu>File>Use Unit... e selecione novamente a unit Proteq_Funcoes.pas. Adione um componente TTimer ao formulário e coloque o seguinte código no evento OnTimer do mesmo:
procedure TForm1.Timer1Timer(Sender: TObject); var senha, codigo_interno: String; begin timer1.Enabled := false; //Desabilita Timer para evitar reentrancia senha := "A0B18CD01"; //envia senha de conexão para chave if Inicia_Proteq(Senha, codigo_interno) then begin if codigo_interno = "tks00002" then edit1.Text := codigo_interno else begin application.MessageBox("Código da CHAVE DE HARDWARE não confere." + #13 + "Este programa será fechado...", "Atenção", mb_ok + mb_iconerror); application.Terminate; end; end else begin application.MessageBox("Não possível estabelecer comunicação com a CHAVE DE HARDWARE" + #13 + "Este programa será fechado...", "Atenção", mb_ok + mb_iconerror); application.Terminate; end; timer1.Enabled := true; end;
Agora basta configurar a propriedade Interval do componente TTimer para indicar de quanto em quanto tempo você deseja que o seu programa verifique a presença da chave.
Controle de Aluguel de Software
Outra aplicação de chaves de hardware é a possibilidade de se implementar de maneira confiável um esquema de controle de aluguel de software, uma vez que podemos utilizar a memória da chave para armazenar informações como número de execuções e prazo de expiração do aluguel.
Vamos agora mostrar como um esquema como este pode ser implementado.
Ao alugar o programa, o usuário recebe uma chave contendo a data da última execução do programa e a data em que o período de aluguel contratado irá terminar. Neste demo, armazenamos estas informações encriptadas nas 16 (dezeseis) primeiras posições de memória da chave sob a forma "dd/mm/aaaadd/mm/aaaa", onde a primeira data representa a última execução e a segunda data representa o fim do aluguel.
Assim, ao ser executado, o programa localiza a chave, faz a leitura das informações para os campos respectivos e testa se a data da última execução é maior ou igual à data do fim do aluguel. Para isso, ele utiliza chamadas à Proteq_Funcoes.pas como mostrado abaixo:
procedure TForm1.FormCreate(Sender: TObject); var Str_Leitura, Str_Gravacao, codigo_interno: String; begin if Inicia_Proteq("A0B18CD01", codigo_interno) then //Inicia Acesso a Chave begin if (codigo_interno = "tks00002") then //Verifica se código interno é o esperado begin if Ler_Memoria(Str_Leitura, 0, 16, True) then //Lê memória e recupera datas begin datetimepicker1.Date := strtodate(copy(Str_Leitura, 1, 10)); datetimepicker2.Date := strtodate(copy(Str_Leitura, 11, 20)); if datetimepicker1.Date>= datetimepicker2.Date then //Testa se prazo terminado begin showmessage("O período de aluguel terminou, entre a senha para renovar o aluguel!); label2.Enabled := False; edit1.Enabled := True; button1.Enabled := True; label3.Enabled := true; datetimepicker2.Enabled := True; button2.Enabled := False; end else begin if Date> datetimepicker1.Date then //Gravação da memória guarda data de última execução begin Str_Gravacao := DateToStr(Date) + DateToStr(datetimepicker2.Date); if not Grava_Memoria(Str_Gravacao, 0, True) then showmessage("Erro na Gravação"); end; end; end else showmessage("Erro na Leitura"); end else showmessage("Código da CHAVE DE HARDWARE não confere); end else showmessage("Não possível estabelecer comunicação com a CHAVE DE HARDWARE"); end;
Figura 4. Demo de controle de aluguel operando dentro de período contratado.
Caso o período de fim de aluguel contratado tenha terminado, o programa pede que o usuário entre a senha de liberação para um novo período de aluguel.
Assim, caso o cliente tenha efetuado o correto pagamento de sua mensalidade, o proprietário do sistema utilizará um programa auxiliar para gerar as senhas de liberação, e encaminha-las ao seu cliente.
Este programa auxiliar contém uma rotina simples de geração de senhas baseada na data escolhida para o fim do aluguel. Esta rotina, seja ela qual for, também deve estar presente no programa do usuário, para que o mesmo possa conferir se a senha digitada corresponde à esperada.
Function Gera_Senha(Name: string; Key: string):string; var I: Integer; begin Result := ""; for I := 1 to Length(Name) do Result := Result + IntToHex(Ord(Name[I]) xor Ord(Key[(I mod Length(Key) + 1)]), 2); end; procedure TForm1.Button1Click(Sender: TObject); begin Edit1.text := Gera_Senha(DatetoStr(Datetimepicker1.date), DatetoStr(Datetimepicker1.date)); end;
Figura 5. Programa utilizado pelo desenvolvedor para liberação de cópias contratadas.
O cliente então, ao receber a senha referente ao período para o qual ele efetuou o pagamento, atualiza o seu sistema, liberando o mesmo para operar normalmente. Neste momento o programa, ao verificar a senha, atualiza a data de fim de aluguel e o sistema volta a operar, dando fim ao ciclo.
Figura 6. Demo de controle de aluguel operando com período expirado.
O que acontece se o usuário, dentro do período contratado, adianta o relógio do computador para uma data além da data de fim do aluguel?
Neste caso o sistema salva a data de última execução e da proxima vez que o sistema for executado ele informará que o período de aluguel expirou.
Por este e outros motivos é importante lembrar que este foi apenas um exemplo de implementação de controle de aluguel, que deve ser usado somente como base para elaboração de um esquema mais completo.
Conclusões
Espero que este artigo tenha servido para esclarecer dúvidas e para que muitos dos leitores se sintam encorajados a utilizar soluções de proteção profissionais em seus aplicativos.
Gostaria também de agradecer à PROTEQ por disponibilizar seu produto para avaliação.
Maiores informações sobre o produto podem ser encontradas no site www.proteq.com.br
Victory Fernandes é desenvolvedor sócio da TKS Software - Soluções de Automação Comercial e Softwares Dedicados. Pode ser contactado em victory@igara.com.br, ou através dos sites www.victory.hpg.com.br - www.enge.cjb.net - www.igara.com.br.