Oficina
KeygenMe #1 (I-2)
Dom 27 Ago 2006 17:46 |
- Detalhes
- Categoria: Pilotando o rato I-2
- Atualização: Terça, 02 Setembro 2008 19:11
- Autor: vovó Vicki
- Acessos: 13227
Este keygen-me é um bom desafio que exige algum conhecimento da linguagem Assembly e das funções da API do Windows.
O programa
O programa foi escrito por Boonz em Assembly para a plataforma Windows e não foi compactado. Publicado em 26 de Julho de 2006 pode ser encontrado no site crackmes.de. Você pode baixá-lo em downloads > informática > crackme > iniciantes, mas, antes de fazê-lo, saiba que o programa NÃO roda em versões anteriores ao Windows XP.
Objetivo do desafio
O objetivo é encontrar a forma como é obtido o serial e escrever um programa keygen que gere seriais corretos para qualquer nome.
Analisando o programa
O programa possui duas caixas de texto, uma para o nome e a outra para o serial. Deixando ambas vazias e clicando em [Check], recebemos o recado de que o nome precisa ter de 4 a 50 caracteres. Colocando qualquer coisa no nome e no serial, recebemos a mensagem Hello, Mr. Bad boy! - a não ser que, por inspiração divina, você consiga acertar na primeira
Planejando o ataque
Bem, se existe uma mensagem dizendo Hello, Mr. Bad boy! é provável que exista uma dizendo algo como Hello, Mr. Goodboy ou Congratulations!. É apenas um palpite, mas, quando não se tem nada, os palpites são a única coisa que nos resta.
Como o programa foi escrito em Assembly (basta conferir com o PEiD), o código costuma ser bem "limpinho". É de se esperar que exista uma rotina que calcule o serial de acordo com o nome fornecido... e é isto que vamos procurar.
As ferramentas
- Como sempre, o PEid vai ser usado para conferir a linguagem usada, as seções do executável e dar uma primeira sapeada no código. Você pode baixá-lo em downloads > informatica > utilitários.
- OllyDbg para rastrear a rotina que calcula o serial. Está à disposição em downloads > informática > debuggers.
- Qualquer linguagem de programação para criar o keygen - fica a seu critério. Dá até para usar a velha e boa JavaScript, com a qual apresentarei o keygen no final deste artigo.
PILOTANDO O MOUSE
Execute o PEid e carregue o executável: vem a confirmação, foi escrito em MASM32 / TASM32. Clique no botão [>] à direita de EP Section só para garantir que as seções são as usuais - .text, .rdata, .data e .rsrc. Agora, clique no botão [>] à direita de First Bytes para chamar o desassemblador. Role o texto um pouco para cima que logo você vai encontrar
00401323: 6817DC4000 PUSH 0040DC17 -> Hello, Mr. Bad boy! 00401328: 68F8DF4000 PUSH 0040DFF8 0040132D: E866000000 CALL 00401398 00401332: 83C408 ADD ESP, 00000008 00401335: 33C0 XOR EAX, EAX 00401337: C3 RET 00401338: 6803DC4000 PUSH 0040DC03 -> Hello, Mr. Goodboy! 0040133D: 68F8DF4000 PUSH 0040DFF8 00401342: E851000000 CALL 00401398 00401347: 83C408 ADD ESP, 00000008 0040134A: 33C0 XOR EAX, EAX 0040134C: C3 RET 0040134D: 6A28 PUSH 00000028 0040134F: 68F8DD4000 PUSH 0040DDF8 00401354: E821000000 CALL 0040137A 00401359: 6865DC4000 PUSH 0040DC65 -> Name must be 4 - 50 chars long! 0040135E: 68F8DF4000 PUSH 0040DFF8 00401363: E830000000 CALL 00401398 00401368: 83C408 ADD ESP, 00000008 0040136B: 33C0 XOR EAX, EAX 0040136D: C3 RET
Parece que está fácil. Vamos marcar o endereço 00401323 e apelar para o OllyDbg.
Correndo o código com o OllyDbg
Rode o OllyDbg e carregue o keygenme1.exe. Procure pelo endereço 00401323, que deve mostrar as mensagens já citadas. Observe que o OllyDbg assinala com um traço vertical colocado logo à direita dos endereços de memória uma subrotina que termina em 0040136D (RET) e que começa em 00401208. É bem aí que vamos colocar um breakpoint com F2. Depois disso, rode o executável com F9. Coloque qualquer coisa como nome (eu usei "teste"), um serial qualquer (eu usei "aaaaa") e clique em [check]. A execução pára exatamente no breakpoint que colocamos.
Execute algumas linhas com F7 (sugiro que use F8 quando chegar numa instrução call):
00401208 /$ 68 F8DC4000 PUSH keygenme.0040DCF8 ; /String = "teste" 0040120D |. E8 80010000 CALL <JMP.&kernel32.lstrlenA> ; \lstrlenA 00401212 |. A3 86DC4000 MOV DWORD PTR DS:[40DC86],EAX 00401217 |. 833D 86DC4000 >CMP DWORD PTR DS:[40DC86],4 0040121E |. 0F8C 29010000 JL keygenme.0040134D 00401224 |. 833D 86DC4000 >CMP DWORD PTR DS:[40DC86],32 0040122B |. 0F8F 1C010000 JG keygenme.0040134D
Em 00401208 podemos ver a string com o nome "teste". Logo em seguida, é chamada a rotina para devolver o comprimento da string (lstrlenA) no registrador EAX (como "teste" tem 5 caracteres, EAX = 5). A seguir, este comprimento é comparado com 4 - se for menor, faremos um salto para a mensagem de Name must be 4 - 50.... A seguir, o comprimento é comparado com 32 (em hexadecimal, ou seja, 50 no sistema decimal). Se for maior, recebemos a mesma mensagem de erro, se não, a execução continua.
Seguindo as instruções com F7 (e F8) podemos observar que alguns cálculos são efetuados e seus resultados são combinados numa string. Pulando todos os cálculos, aqui estão as operações efetuadas:
... 004012B3 |. 68 FCDB4000 PUSH keygenme.0040DBFC ; /Format = "Bon-" 004012B8 |. 68 F8DD4000 PUSH keygenme.0040DDF8 ; |s = keygenme.0040DDF8 004012BD |. E8 D6000000 CALL <JMP.&user32.wsprintfA> ; \wsprintfA 004012C2 |. 83C4 08 ADD ESP,8 004012C5 |. 68 F8E04000 PUSH keygenme.0040E0F8 ; /StringToAdd = "FFFFFE58" 004012CA |. 68 F8DD4000 PUSH keygenme.0040DDF8 ; |ConcatString = "Bon-FFFFFE58-FB74E600-41720F48" 004012CF |. E8 B2000000 CALL <JMP.&kernel32.lstrcatA> ; \lstrcatA 004012D4 |. 68 01DC4000 PUSH keygenme.0040DC01 ; /StringToAdd = "-" 004012D9 |. 68 F8DD4000 PUSH keygenme.0040DDF8 ; |ConcatString = "Bon-FFFFFE58-FB74E600-41720F48" 004012DE |. E8 A3000000 CALL <JMP.&kernel32.lstrcatA> ; \lstrcatA 004012E3 |. 68 F8E14000 PUSH keygenme.0040E1F8 ; /StringToAdd = "FB74E600" 004012E8 |. 68 F8DD4000 PUSH keygenme.0040DDF8 ; |ConcatString = "Bon-FFFFFE58-FB74E600-41720F48" 004012ED |. E8 94000000 CALL <JMP.&kernel32.lstrcatA> ; \lstrcatA 004012F2 |. 68 01DC4000 PUSH keygenme.0040DC01 ; /StringToAdd = "-" 004012F7 |. 68 F8DD4000 PUSH keygenme.0040DDF8 ; |ConcatString = "Bon-FFFFFE58-FB74E600-41720F48" 004012FC |. E8 85000000 CALL <JMP.&kernel32.lstrcatA> ; \lstrcatA 00401301 |. 68 F8E24000 PUSH keygenme.0040E2F8 ; /StringToAdd = "41720F48" 00401306 |. 68 F8DD4000 PUSH keygenme.0040DDF8 ; |ConcatString = "Bon-FFFFFE58-FB74E600-41720F48" 0040130B |. E8 76000000 CALL <JMP.&kernel32.lstrcatA> ; \lstrcatA 00401310 |. B8 F8DD4000 MOV EAX,keygenme.0040DDF8 ; ASCII "Bon-FFFFFE58-FB74E600-41720F48" 00401315 |. BB F8DE4000 MOV EBX,keygenme.0040DEF8 ; ASCII "aaaaa" 0040131A |. 53 PUSH EBX ; /String2 => "aaaaa" 0040131B |. 50 PUSH EAX ; |String1 => "Bon-FFFFFE58-FB74E600-41720F48" 0040131C |. E8 6B000000 CALL <JMP.&kernel32.lstrcmpA> ; \lstrcmpA 00401321 |. 74 15 JE SHORT keygenme.00401338
Hehehe :cool: No endereço 00401310 está o serial para o nome teste: Bon-FFFFFE58-FB74E600-41720F48. Não dá para resistir à tentação. Que tal transformar o keygenme1.exe no seu próprio key generator?
A instrução que nos mostra o serial diz para transferir para EAX a string que está no endereço de memória 0040DDF8. Marque este endereço pois vamos usá-lo logo mais. Além disso, após comparar o serial calculado com o fornecido, há uma salto condicional para 00401338 se os dois coincidirem. Se transformarmos este salto condicional em salto obrigatório, trocando JE por JMP, seremos levados diretamente para a mensagem Hello, Mr. Goodboy! onde faremos uma segunda alteração. Por enquanto, faça o seguinte:
- Selecione a linha 00401321 e aperte a tecla de espaço.
- Na janela de edição, troque JE (jump equal = salte se igual) por JMP (jump = salte).
- Clique no botão [Assemble] e feche a janela.
00401321 |. 74 15 JE SHORT keygenme.00401338 será transformado em 00401321 |. EB 15 JMP SHORT keygenme.00401338
Agora vamos até o endereço 00401338 e, usando o mesmo método descrito acima, troque o endereço 0040DC03 pelo endereço do serial
00401338: 68 03DC4000 PUSH 0040DC03 -> Hello, Mr. Goodboy! será transformado em 00401338: 68 DDF84000 PUSH 0040DDF8 -> Bon-FFFFFE58-FB74E600-41720F48
Rode o executável novamente usando Ctrl+F2, digite o nome que quiser, um serial qualquer, clique no botão [check] e o serial bichado será substituído pelo correto :cool:
Calculando o serial
Até agora só fizemos um pouco de hardcoding introduzindo dois patches para transformar o executável no seu próprio gerador de seriais, mas esta não é a tarefa proposta. Para escrever um key generator autêntico é preciso entender o tipo de cálculo efetuado para criar o serial. Para isto, vamos seguir as instruções dos cálculos passo a passo. Vamos por partes com o código:
... 00401231 |. 33C0 XOR EAX,EAX 00401233 |. 33DB XOR EBX,EBX 00401235 |. 33C9 XOR ECX,ECX 00401237 |. BF F8DC4000 MOV EDI,keygenme.0040DCF8 ; ASCII "teste" 0040123C |. 8B15 86DC4000 MOV EDX,DWORD PTR DS:[40DC86] ...
Siga o passo a passo apertando as teclas indicadas:
- (F7) XOR EAX,EAX - Zera o registrador EAX (XOR de um registrador com ele mesmo sempre resulta em zero).
- (F7) XOR EBX,EBX - Zera o registrador EBX.
- (F7) XOR ECX,ECX - Zera o registrador ECX.
- (F7_ MOV EDI,keygenme.0040DCF8 - Coloca em EDI o nome do usuário que no nosso exemplo é "teste").
- (F7) MOV EDX,DWORD PTR DS:[40DC86] - Coloca em EDX o valor armazenado na posição de memória 0040DC86. Só para dar uma treinadinha, role o conteúdo da memória mostrada no painel inferior esquerdo do OllyDbg até encontrar este endereço. Você deve ver logo depois de Name must be... o seguinte:
0040DC60 00 4E 46 4F 00 4E 61 6D .NFO.Nam 0040DC68 65 20 6D 75 73 74 20 62 e must b 0040DC70 65 20 34 20 2D 20 35 30 e 4 - 50 0040DC78 20 63 68 61 72 73 20 6C chars l 0040DC80 6F 6E 67 21 00 0D 05 00 ong! ; <- aqui!!!
Depois de preparar os registradores (o ECX costuma ser usado como contador e o EDX como referência), encontramos o seguinte loop de instruções:
... 00401242 |> 0FB60439 /MOVZX EAX,BYTE PTR DS:[ECX+EDI] 00401246 |. 83E8 19 |SUB EAX,19 00401249 |. 2BD8 |SUB EBX,EAX 0040124B |. 41 |INC ECX 0040124C |. 3BCA |CMP ECX,EDX 0040124E |.^75 F2 \JNZ SHORT keygenme.00401242 ...
- (F7) MOVZX EAX,BYTE PTR DS:[ECX+EDI] - Coloca o valor ASCII hexadecimal do primeiro caracter do nome em EAX. O caracter ASCII de "t" = 74
- (F7) SUB EAX,19 - Subtrai 19h (25 decimal) de EAX, ou seja, EAX = 74 - 19 = 5B.
- (F7) SUB EBX,EAX - Subtrai EAX (5B) de EBX, ou seja, EBX = 00 - 5B = FFFFFFA5.
- (F7) INC ECX - Incrementa ECX, ou seja, ECX = 0 + 1 = 1.
- (F7) CMP ECX,EDX - Compara ECX com EDX ou seja, compara 1 com 5.
- (F7) JNZ SHORT keygenme.00401242 - Se ECX e EDX não tiverem valores iguais, salte para o início do loop.
É claro que este loop será repetido até que todos os caracteres do nome do usuário tiverem sido utilizados para o cálculo. Acompanhe o que acontece:
EAX EAX - 19 EBX - EAX ECX |====+===|============|=============|=======| | 74 (t) | 5B | FFFFFFA5 | 1 | | 65 (e) | 4C | FFFFFF59 | 2 | | 73 (s) | 5A | FFFFFEFF | 3 | | 74 (t) | 5B | FFFFFEA4 | 4 | | 65 (e) | 4C | FFFFFE58 | 5 | |========|============|=============|=======|
Quando ECX = 5, o loop termina.
Saindo do loop, a linha de execução prossegue colocando alguns valores na pilha como parâmetros para a chamada à função wsprintfA que transforma valores hexadecimais em strings:
... 00401250 |. 53 PUSH EBX ; /<%lX> = FFFFFE58 00401251 |. 68 F8DB4000 PUSH keygenme.0040DBF8 ; |Format = "%lX" 00401256 |. 68 F8E04000 PUSH keygenme.0040E0F8 ; |s = keygenme.0040E0F8 0040125B |. E8 38010000 CALL <JMP.&user32.wsprintfA> ; \wsprintfA ...
- (F7) PUSH EBX - Coloca o valor FFFFFE58 na pilha. Observe no painel inferior direito do OllyDbg que o valor entrou na posição superior.
- (F7) PUSH keygenme.0040DBF8 - Coloca mais o parâmetro de formato na pilha. Observe mais uma vez o painel da pilha.
- (F7) PUSH keygenme.0040E0F8 - Coloca na pilha o endereço onde a string deve ser armazenada. Posicione o painel da memória do OllyDbg (o inferior esquerdo) para poder ver o endereço 0040E0F8.
- (F8) CALL
- A string "FFFFFE58" é colocada no endereço de memória 0040E0F8.
Obtida a primeira string, vamos analisar o cálculo para obter a segunda.
... 00401260 |. 83C4 0C ADD ESP,0C 00401263 |. 33C0 XOR EAX,EAX 00401265 |. 33D2 XOR EDX,EDX 00401267 |. 33C9 XOR ECX,ECX 00401269 |. 03C3 ADD EAX,EBX 0040126B |. 0FAFC3 IMUL EAX,EBX 0040126E |. 03C8 ADD ECX,EAX 00401270 |. 2BD3 SUB EDX,EBX 00401272 |. 33D0 XOR EDX,EAX 00401274 |. 0FAFD8 IMUL EBX,EAX 00401277 |. 53 PUSH EBX ; /<%lX> 00401278 |. 68 F8DB4000 PUSH keygenme.0040DBF8 ; |Format = "%lX" 0040127D |. 68 F8E14000 PUSH keygenme.0040E1F8 ; |s = keygenme.0040E1F8 00401282 |. E8 11010000 CALL <JMP.&user32.wsprintfA> ; \wsprintfA ...
- (F7) ADD ESP,0C - Adiciona 0Ch (12 decimal) ao ponteiro da pilha.
- (F7) XOR EAX,EAX - Zera o registrador EAX.
- (F7) XOR EDX,EDX - Zera o registrador EDX.
- (F7) XOR ECX,ECX - Zera o registrador ECX.
- (F7) ADD EAX,EBX - Adiciona o valor de EBX a EAX, ou seja, EAX = 0 + FFFFFE58 = FFFFFE58.
- (F7) IMUL EBX,EAX - Multiplica EBX por EAX (ou seja, eleve EBX ao quadrado), o que resulta em FFFFFCB00002BE40. Mais uma vez, este baita número não cabe em EAX e o registrador só segura a parte final deixando EAX = 0002BE40.
- (F7) ADD ECX,EAX - Adiciona o valor de EAX ao de ECX, ou seja, ECX = 0 + 0002BE40 = 0002BE40.
- (F7) SUB EDX,EBX - Subtrai EBX de EDX, ou seja, EDX = 0 - 0002BE40 = 000001A8.
- (F7) XOR EDX,EAX - Faça a operação XOR entre EDX e EAX. Na operação XOR, os bits dos dois valores são comparados e, quando forem iguais, o resultado é zero; quando forem diferentes, o resultado é 1. Use a calculadora do Windows no modo científico para obter os bits dos valores:
EDX 0001A8 0 0 0 0 0 0 0 0 0 1 1 0 1 0 1 0 0 0 EAX 02BE40 1 0 1 0 1 1 1 1 1 0 0 1 0 0 0 0 0 0 ------------------------------------- XOR = 1 0 1 0 1 1 1 1 1 1 1 1 1 0 1 0 0 0 ==> 02BFE8
Agora EDX = 2BFE8. - (F7) IMUL EBX,EAX - Multiplica EBX com EAX, ou seja, EBX = FFFFFE58 x 02BE40 = FB74E600.
- (F7) PUSH EBX - Coloca o valor de EBX, FB74E600, na pilha.
- (F7) PUSH keygenme.0040DBF8 - Coloca o formato na pilha.
- (F7) PUSH keygenme.0040E1F8 - Põe o endereço de memória onde deve ser colocada a string do valor de EBX.
- (F8) CALL <JMP.&user32.wsprintfA> - Chama a função wsprintfA para transformar em string o valor hexadecimal de EBX.
Agora a pergunta: para que serviu esta história de subtrair EBX de EDX e depois fazer um XOR de EDX com EAX? Toda esta frescura de bits pra cá, bits pra lá, pra depois não usar o valor calculado?
Encare com otimismo. Isto é o chamado junk code ou código lixo que alguns autores colocam na programação para torrar a paciência de quem está bisbilhotando o código. Por outro lado (e aí está o otimismo), foi uma bela oportunidade de rever o que vem a ser uma operação XOR e de entender porque um XOR de um registrador com ele mesmo resulta em zero (bits iguais sempre resultam em zero)
Já temos dois valores calculados e transformados em string: FFFFFE58 e FB74E600. Agora é a hora de obter uma terceira string (espero que não seja outro junk code...)
... 00401287 |. 83C4 0C ADD ESP,0C 0040128A |. 33C0 XOR EAX,EAX 0040128C |. 33DB XOR EBX,EBX 0040128E |. 33D2 XOR EDX,EDX 00401290 |. 33C9 XOR ECX,ECX 00401292 |. B8 F8E04000 MOV EAX,keygenme.0040E0F8 ; ASCII "FFFFFE58" 00401297 |. 03D8 ADD EBX,EAX 00401299 |. 33CB XOR ECX,EBX 0040129B |. 0FAFCB IMUL ECX,EBX 0040129E |. 2BC8 SUB ECX,EAX 004012A0 |. 51 PUSH ECX ; /<%lX> 004012A1 |. 68 F8DB4000 PUSH keygenme.0040DBF8 ; |Format = "%lX" 004012A6 |. 68 F8E24000 PUSH keygenme.0040E2F8 ; |s = keygenme.0040E2F8 004012AB |. E8 E8000000 CALL <JMP.&user32.wsprintfA> ; \wsprintfA ...
- (F7) ADD ESP,0C - Adiciona 0Ch (12 decimal) ao ponteiro da pilha.
- (F7) XOR EAX,EAX - Zera o registrador EAX.
- (F7) XOR EBX,EBX - Zera o registrador EBX.
- (F7) XOR EDX,EDX - Zera o registrador EDX.
- (F7) XOR ECX,ECX - Zera o registrador ECX.
- (F7) MOV EAX,keygenme.0040E0F8 - Coloca em EAX o endereço 0040E0F8 onde se encontra a string "FFFFFE58".
- (F7) ADD EBX,EAX - Soma EBX com AEX, ou seja, EBX tem agora o mesmo endereço.
- (F7) XOR ECX,EBX - Faz um XOR entre ECX e EBX. Hahaha... agora não nos pegam de calça curta. Se ECX está todo zerado e fizermos um XOR com EBX que tem um valor, o valor de EBX simplesmente é transferido para ECX. O mesmo poderia ter sido feito com ADD ECX,EBX
- (F7) IMUL ECX,EBX - Multiplica ECX por EBX, ou seja, ECX = 40E0F8 x 40E0F8 = 107141B2F040. Sobrou bit de novo e o registrador EBX só guarda 41B2F040.
- (F7) SUB ECX,EAX - Subtrai EAX de ECX. Neste caso, ECX = 41B2F040 - 0040E0F8 = 41720F48.
O restante do código já dá para tirar de letra: os parâmetros necessários para a função wsprintfA são colocados na pilha e a dita cuja é chamada para transformar o valor hexadecimal de ECX numa string, ou seja, a terceira string calculada é "41720F48".
Seguindo com o código temos:
... 004012B0 |. 83C4 0C ADD ESP,0C 004012B3 |. 68 FCDB4000 PUSH keygenme.0040DBFC ; /Format = "Bon-" 004012B8 |. 68 F8DD4000 PUSH keygenme.0040DDF8 ; |s = keygenme.0040DDF8 004012BD |. E8 D6000000 CALL; \wsprintfA ...
- (F7) ADD ESP,0C - Adiciona 0Ch (12 decimal) ao endereço da pilha.
- (F7) PUSH keygenme.0040DBFC - Põe na pilha o formato "Bon-".
- (F7) PUSH keygenme.0040DDF8 - Põe na pilha o endereço onde deve ser colocada a string.
- (F8) CALL
- Coloca a string "Bon-" no endereço indicado.
Parece que a string final já está sendo montada. Procure o endereço 0040DDF8 (se é que você já não o fez), certifique-se de que "Bon-" já está no lugar e continue monitorando este bloco de endereços de memória.
... 004012C2 |. 83C4 08 ADD ESP,8 004012C5 |. 68 F8E04000 PUSH keygenme.0040E0F8 ; /StringToAdd = "FFFFFE58" 004012CA |. 68 F8DD4000 PUSH keygenme.0040DDF8 ; |ConcatString = "Bon-" 004012CF |. E8 B2000000 CALL; \lstrcatA 004012D4 |. 68 01DC4000 PUSH keygenme.0040DC01 ; /StringToAdd = "-" 004012D9 |. 68 F8DD4000 PUSH keygenme.0040DDF8 ; |ConcatString = "Bon-" 004012DE |. E8 A3000000 CALL ; \lstrcatA 004012E3 |. 68 F8E14000 PUSH keygenme.0040E1F8 ; /StringToAdd = "FB74E600" 004012E8 |. 68 F8DD4000 PUSH keygenme.0040DDF8 ; |ConcatString = "Bon-" 004012ED |. E8 94000000 CALL ; \lstrcatA 004012F2 |. 68 01DC4000 PUSH keygenme.0040DC01 ; /StringToAdd = "-" 004012F7 |. 68 F8DD4000 PUSH keygenme.0040DDF8 ; |ConcatString = "Bon-" 004012FC |. E8 85000000 CALL ; \lstrcatA 00401301 |. 68 F8E24000 PUSH keygenme.0040E2F8 ; /StringToAdd = "41720F48" 00401306 |. 68 F8DD4000 PUSH keygenme.0040DDF8 ; |ConcatString = "Bon-" 0040130B |. E8 76000000 CALL ; \lstrcatA ...
- (F7) ADD ESP,8 - Adianta o ponteiro da pilha em 8.
- (F7) PUSH keygenme.0040E0F8 - Põe na pilha o endereço da primeira string ("FFFFFE58").
- (F7) PUSH keygenme.0040DDF8 - Põe na pilha o endereço onde a string resultante deve ser colocada (já está com "Bon-").
- (F8) CALL
- Chama a função lstrcatA para concaternar as duas strings fornecidas. Em 0040DDF8 deve aparecer "Bon-FFFFFE58". - (F7) PUSH keygenme.0040DC01 - Põe na pilha o endereço da string "-".
- (F7) PUSH keygenme.0040DDF8 - Põe na pilha o endereço onde a string resultante deve ser colocada (neste ponto já está como "Bon-FFFFFE58".
- (F7) CALL
- Chama a função lstrcatA para concaternar as duas strings fornecidas. Em 0040DDF8 deve aparecer "Bon-FFFFFE58-".
E por aí vai. O restante é a repetição do método para concatenar strings até que o serial resulta em Bon-FFFFFE58-FB74E600-41720F48. Depois disto, o serial fornecido é comparado com o calculado e você já conhece o resto da história.
Key generator em JavaScript
A linguagem JavaScript é tão boa quanto qualquer outra para programar um keygen. Além disso, o gerador de seriais fica na web para quem quiser testar os mais diversos nomes de usuário no aplicativo do Boonz.
Para aqueles que estão curiosos como foi escrito este keygen, aqui vai o código do JavaScript. O botão [Gerar Serial] chama a função teste(). O que mais deu trabalho foi calcular o complemento a dois dos números negativos
function teste() { var usu = document.form1.nome.value; var valor = 0; for(var i=0; i=0; i--) if(vaium == 1) { if(inv.charAt(i) == "1") neg = "0" + neg; else { neg = "1" + neg; vaium = 0; } } else neg = inv.charAt(i) + neg; return neg; } function char2ascii (c) { // restrict input to a single character c = c . charAt (0); // loop through all possible ASCII values for (var i = 0; i < 256; ++ i) { // convert i into a 2-digit hex string var h = i . toString (16); if (h . length == 1) h = "0" + h; // insert a % character into the string h = "%" + h; // determine the character represented by the escape code h = unescape (h); // if the characters match, we've found the ASCII value if (h == c) break; } return(i); } function bin2hex(nibble) { if(nibble == "0000") return "0"; if(nibble == "0001") return "1"; if(nibble == "0010") return "2"; if(nibble == "0011") return "3"; if(nibble == "0100") return "4"; if(nibble == "0101") return "5"; if(nibble == "0110") return "6"; if(nibble == "0111") return "7"; if(nibble == "1000") return "8"; if(nibble == "1001") return "9"; if(nibble == "1010") return "A"; if(nibble == "1011") return "B"; if(nibble == "1100") return "C"; if(nibble == "1101") return "D"; if(nibble == "1110") return "E"; if(nibble == "1111") return "F"; }
Grande abraço a todos