Serial Fishing
Estava procurando rever algumas coisas de engenharia reversa e fui ‘brincar’ com serial Fishing. Serial fishing é possível quando a aplicação, ao tentar verificar se o serial digitado foi fornecido corretamente, gera o serial original para fazer uma comparação. Vamos ver como podemos tirar proveito disto.
Como o serial gerado pela aplicação esta residente na memória, basta abrir o processo e pegar ele bonitinho na memória. A parte mais emocionante é encontrar o serial na memória (isto se ele estiver lá). Para fins de uso pessoal estudo, achando tendo o serial na memória já basta, porém como bons nerds atoas que somos, nós escrevemos um código que pegue e exiba o serial na tela.
O programa que estava testar é o jogo Xadrez Master na versão 5.8.6.0, ao abri-lo no OllyDbg e digitar qualquer nome e serial, é exibida uma mensagem informando que o serial está inválida. Sem fechar a janela, voltei para o Olly, dei pause no processo e então pude analisar o seguinte na memória:
CPU Dump: 0012EA48 |00F2F1A8 ASCII "Maycon Maia Vitali (0ut0fBound)" 0012EA4C |00F36868 ASCII "XAD-BXLT4-TLKXJ" 0012EA50 |00F1C8A4 ASCII "XAD" 0012EA54 |00F2F18C ASCII "AABBCCDDEEFF" 0012EA58 |00EDCB64 ASCII "AAB" 0012EA5C |00F1CEAC ASCII "Maycon Maia Vitali (0ut0fBound)" 0012EA60 |00F2F170 ASCII "XAD-BXLT4-TLKXJ" 0012EA64 |00F1CE90 ASCII "AABBCCDDEEFF" 0012EA68 |00ED1D64 ASCII "AABBCCDDEEFF" 0012EA6C |00ED1D80 ASCII "AABBCCDDEEFF" 0012EA70 |00F1CE74 ASCII "AABBCCDDEEFF" 0012EA74 |00ED1D0C ASCII "Maycon Maia Vitali (0ut0fBound)" 0012EA78 |00ED1D38 ASCII "Maycon Maia Vitali (0ut0fBound)"
Estes dados foram obtidos da pilha, e podemos notar o serial XAD-BXLT4-TLKXJ para o nome “Maycon Maia Vitali (0ut0fBound)” em diversos endereços diferentes. Vamos pegar só um exemplo:
0012EA48 |00F2F1A8 ASCII "Maycon Maia Vitali (0ut0fBound)" 0012EA4C |00F36868 ASCII "XAD-BXLT4-TLKXJ"
Neste caso, nos endereços 0012EA48 e 0012EA4C temos respectivamente os endereços de memória onde estão o nome e serial válidos. Portanto nosso “Serial Fisher” deve obter antes os endereços das strings na memória para depois le-las em sí.
Sem muitas firulas, segue um código-rápido que fiz para fazer Serial Fishing desse software. Lembrando que é necessário digitar um serial qualquer e pressionar o botão de registrar e, sem fechar a caixa da mensagem informando serial inválido, rodar o fisher(pescador):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | /** * Serial fisher para RKSoft Xadrez Master 5.8.6.0 * Por Maycon M. Vitali (0ut0fBound) * * ATENÇÃO: Este código foi criado para fins de estudo, caso deseje * obter o software é necessário que se page a licensa estipulada * pelo fabricante. */ #include <stdio.h> #include <string.h> #include <windows.h> #define NAME_PTR_ADDR 0x0012EA48 #define SERIAL_PTR_ADDR 0x0012EA4C #define TITULO_JANELA "Xadrez Master" #define MAX_SIZE 100 int main() { HWND cmeHandle; // Handle da janela do processo DWORD cmePid; // PID do processo crackme HANDLE cmdProcHandle; // Handle do processo ( depois de aberto ) long lngAddrNome, lngAddrSerial; char strNome[MAX_SIZE], strSerial[MAX_SIZE]; char strMensagem[MAX_SIZE*2 + 20]; // Procuramos pela janela do crackme if (!(cmeHandle = FindWindow(0, TITULO_JANELA))) { MessageBoxA( 0, "Execute o xadrez.exe e tente registrar com qualquer serial antes.", "Serial Fishing", 0 ); exit(-1); } // Pega e abre processo GetWindowThreadProcessId(cmeHandle, &cmePid); cmdProcHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, cmePid); // Obtém os endereços das informações na pilha ReadProcessMemory(cmdProcHandle, (void *)NAME_PTR_ADDR, &lngAddrNome, sizeof(lngAddrNome), NULL); ReadProcessMemory(cmdProcHandle, (void *)SERIAL_PTR_ADDR, &lngAddrSerial, sizeof(lngAddrSerial), NULL); // Pega os valores nos endereços obtidos ReadProcessMemory(cmdProcHandle, (const void *)lngAddrNome, strNome, sizeof(strNome) - 1, NULL); ReadProcessMemory(cmdProcHandle, (const void *)lngAddrSerial, strSerial, sizeof(strSerial) - 1, NULL); snprintf (strMensagem, sizeof(strMensagem) - 1, "Nome: %s\nSerial: %s", strNome, strSerial); MessageBoxA(0, strMensagem, "Enjoy!", 0); printf ("Nome ...: %s\n", strNome); printf ("Serial .: %s\n", strSerial); return 0; } |
Como dito no comentário, não forneci esse código com fins de prejudicar a equipe que desenvolve a ferramenta. Tentarei futuramente disponibilizar análise de malwares e afins para não ter problemas futuros.