A Aldeia Numaboa ancestral ainda está disponível para visitação. É a versão mais antiga da Aldeia que eu não quis simplesmente descartar depois de mais de 10 milhões de pageviews. Como diz a Sirley, nossa cozinheira e filósofa de plantão: "Misericórdia, ai que dó!"

Se você tiver curiosidade, o endereço é numaboa.net.br.

Leia mais...

Oficina

KeygenMe #1 (I-2)

Dom

27

Ago

2006


17:46

(16 votos, média 4.81 de 5) 


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 smile

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:

  1. Selecione a linha 00401321 e aperte a tecla de espaço.
  2. Na janela de edição, troque JE (jump equal = salte se igual) por JMP (jump = salte).
  3. 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:

  1. (F7) XOR EAX,EAX - Zera o registrador EAX (XOR de um registrador com ele mesmo sempre resulta em zero).
  2. (F7) XOR EBX,EBX - Zera o registrador EBX.
  3. (F7) XOR ECX,ECX - Zera o registrador ECX.
  4. (F7_ MOV EDI,keygenme.0040DCF8 - Coloca em EDI o nome do usuário que no nosso exemplo é "teste").
  5. (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
...
  1. (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
  2. (F7) SUB EAX,19 - Subtrai 19h (25 decimal) de EAX, ou seja, EAX = 74 - 19 = 5B.
  3. (F7) SUB EBX,EAX - Subtrai EAX (5B) de EBX, ou seja, EBX = 00 - 5B = FFFFFFA5.
  4. (F7) INC ECX - Incrementa ECX, ou seja, ECX = 0 + 1 = 1.
  5. (F7) CMP ECX,EDX - Compara ECX com EDX ou seja, compara 1 com 5.
  6. (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
...
  1. (F7) PUSH EBX - Coloca o valor FFFFFE58 na pilha. Observe no painel inferior direito do OllyDbg que o valor entrou na posição superior.
  2. (F7) PUSH keygenme.0040DBF8 - Coloca mais o parâmetro de formato na pilha. Observe mais uma vez o painel da pilha.
  3. (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.
  4. (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
...
  1. (F7) ADD ESP,0C - Adiciona 0Ch (12 decimal) ao ponteiro da pilha.
  2. (F7) XOR EAX,EAX - Zera o registrador EAX.
  3. (F7) XOR EDX,EDX - Zera o registrador EDX.
  4. (F7) XOR ECX,ECX - Zera o registrador ECX.
  5. (F7) ADD EAX,EBX - Adiciona o valor de EBX a EAX, ou seja, EAX = 0 + FFFFFE58 = FFFFFE58.
  6. (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.
  7. (F7) ADD ECX,EAX - Adiciona o valor de EAX ao de ECX, ou seja, ECX = 0 + 0002BE40 = 0002BE40.
  8. (F7) SUB EDX,EBX - Subtrai EBX de EDX, ou seja, EDX = 0 - 0002BE40 = 000001A8.
  9. (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.
  10. (F7) IMUL EBX,EAX - Multiplica EBX com EAX, ou seja, EBX = FFFFFE58 x 02BE40 = FB74E600.
  11. (F7) PUSH EBX - Coloca o valor de EBX, FB74E600, na pilha.
  12. (F7) PUSH keygenme.0040DBF8 - Coloca o formato na pilha.
  13. (F7) PUSH keygenme.0040E1F8 - Põe o endereço de memória onde deve ser colocada a string do valor de EBX.
  14. (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?

smile 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) smile


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
...
  1. (F7) ADD ESP,0C - Adiciona 0Ch (12 decimal) ao ponteiro da pilha.
  2. (F7) XOR EAX,EAX - Zera o registrador EAX.
  3. (F7) XOR EBX,EBX - Zera o registrador EBX.
  4. (F7) XOR EDX,EDX - Zera o registrador EDX.
  5. (F7) XOR ECX,ECX - Zera o registrador ECX.
  6. (F7) MOV EAX,keygenme.0040E0F8 - Coloca em EAX o endereço 0040E0F8 onde se encontra a string "FFFFFE58".
  7. (F7) ADD EBX,EAX - Soma EBX com AEX, ou seja, EBX tem agora o mesmo endereço.
  8. (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 smile
  9. (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.
  10. (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
...
  1. (F7) ADD ESP,0C - Adiciona 0Ch (12 decimal) ao endereço da pilha.
  2. (F7) PUSH keygenme.0040DBFC - Põe na pilha o formato "Bon-".
  3. (F7) PUSH keygenme.0040DDF8 - Põe na pilha o endereço onde deve ser colocada a string.
  4. (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
...
  1. (F7) ADD ESP,8 - Adianta o ponteiro da pilha em 8.
  2. (F7) PUSH keygenme.0040E0F8 - Põe na pilha o endereço da primeira string ("FFFFFE58").
  3. (F7) PUSH keygenme.0040DDF8 - Põe na pilha o endereço onde a string resultante deve ser colocada (já está com "Bon-").
  4. (F8) CALL - Chama a função lstrcatA para concaternar as duas strings fornecidas. Em 0040DDF8 deve aparecer "Bon-FFFFFE58".
  5. (F7) PUSH keygenme.0040DC01 - Põe na pilha o endereço da string "-".
  6. (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".
  7. (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.

Keygen para o keygen-me 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 sad

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

vovo

mfx broker компаниясковорода нержавеющаяооо полигон плюссупермаркет лобановскийfb consultалександр лобановскийофициальный никас

Informações adicionais