Pergunta

Eu estou tentando aprender sobre engenharia reversa, utilizando Minesweeper como um aplicativo de amostra. Encontrei este href="http://blogs.msdn.com/debuggingtoolbox/archive/2007/03/28/windbg-script-playing-with-minesweeper.aspx" rel="noreferrer"> artigo em um simples comando WinDbg que revela todas as minas, mas é velho, não é explicado em detalhes e realmente não é o que eu estou procurando.

IDA Pro disassembler e WinDbg depurador e tenho Winmine.exe carregado em ambos. Alguém pode fornecer algumas dicas práticas para qualquer um desses programas em termos de encontrar a localização da estrutura de dados que representa o campo minado?

Em WinDbg posso definir pontos de interrupção, mas é difícil para mim imaginar a que ponto para definir um ponto de interrupção e em que local da memória. Da mesma forma, quando eu ver o código estático no IDA Pro, eu não tenho certeza de onde começar mesmo para encontrar a função ou estrutura de dados que representa o campo de minas.

Há alguma engenharia reversa em Stackoverflow que pode me apontar na direção certa?

Foi útil?

Solução

Parte 1 de 3


Se você é sério em engenharia reversa - esquecer formadores e motores de fraude.

Boa engenharia reversa deve primeiro conhecer OS, funções essenciais da API, estrutura do programa geral (o que é executado loop, estruturas de janelas, evento rotinas de manutenção), formato de arquivo (PE). clássicos do Petzold "Programação Windows" pode ajudar (www.amazon.com/exec/obidos/ISBN=157231995X), bem como MSDN online.

Primeiro você deve pensar sobre onde rotina de inicialização do campo minado pode ser chamado. Pensei seguinte:

  • Quando você iniciar o jogo
  • Quando você clica cara feliz
  • Ao clicar em Jogo-> Novo ou pressione F2
  • Quando você altera nível de dificuldade

Eu decidi verificar comando acelerador F2.

Para acelerador código de manipulação você está para encontrar o procedimento manipulação mensagem de janela (WndProc). Ele pode ser rastreada para baixo por chamadas CreateWindowEx e RegisterClass.

Para ler:

Abra IDA, a janela Imports, encontrar "CreateWindow *", salto a ele e use "Ir xref ao operando (X)" comando para ver onde é chamado. Deve haver apenas uma chamada.

Agora, olhe para cima para a função RegisterClass e é parâmetro WndClass.lpfnWndProc. Eu já chamado função MainWndProc no meu caso.

.text:0100225D                 mov     [ebp+WndClass.lpfnWndProc], offset mainWndProc
.text:01002264                 mov     [ebp+WndClass.cbClsExtra], edi
.text:01002267                 mov     [ebp+WndClass.cbWndExtra], edi
.text:0100226A                 mov     [ebp+WndClass.hInstance], ecx
.text:0100226D                 mov     [ebp+WndClass.hIcon], eax

.text:01002292                 call    ds:RegisterClassW

Hit Enter no nome da função (uso 'N' para renomeá-lo para algo melhor)

Agora, dê uma olhada

.text:01001BCF                 mov     edx, [ebp+Msg]

Este é o identificador da mensagem, que em caso de botão F2 de imprensa deve conter o valor WM_COMMAND. Você é encontrar onde ele é comparado com 111h. Isso pode ser feito tanto por rastreamento para baixo EDX no IDA ou por configuração condicional ponto de interrupção no WinDbg e pressionando F2 no jogo.

De qualquer maneira leva a algo como

.text:01001D5B                 sub     eax, 111h
.text:01001D60                 jz      short loc_1001DBC

Botão direito do mouse em 111h e uso "constante simbólica" -> "Use constante simbólica padrão", digite WM_ e Enter. Agora você deve ter

.text:01001D5B                 sub     eax, WM_COMMAND
.text:01001D60                 jz      short loc_1001DBC

É uma maneira fácil de descobrir valores mensagem id.

Para entender acelerador verificação manipulação out:

É um monte de texto para uma única resposta. Se você estiver interessado eu posso escrever um outro par de mensagens. Longa história curta campo minado armazenadas como um array de bytes [24x36], shows 0x0F que byte não é usado (jogando campo menor), 0x10 - campo vazio, 0x80 -. Mina

Parte 2 de 3


Ok, vamos continuar com o botão F2.

De acordo com a Usando o teclado Accelerators quando F2 botão é pressionado a função wndProc

... recebe um WM_COMMAND ou WM_SYSCOMMAND mensagem. A palavra de ordem da wParam parâmetro contém o identificador do acelerador.

Ok, nós já encontrado onde WM_COMMAND é processada, mas como para determinar o valor do parâmetro wParam correspondente? Este é o lugar onde Resource hackers entra em jogo. Alimentá-lo com binário e mostra-lhe tudo. Como a tabela aceleradores para mim.

texto alt http://files.getdropbox.com/u/1478671/2009-07-29_161532.jpg

Você pode ver aqui, que corresponde tecla F2 para 510 em wParam.

Agora vamos voltar ao código, que lida com WM_COMMAND. Ele compara wParam com diferentes constantes.

.text:01001DBC HandleWM_COMMAND:                       ; CODE XREF: mainWndProc+197j
.text:01001DBC                 movzx   eax, word ptr [ebp+wParam]
.text:01001DC0                 mov     ecx, 210h
.text:01001DC5                 cmp     eax, ecx
.text:01001DC7                 jg      loc_1001EDC
.text:01001DC7
.text:01001DCD                 jz      loc_1001ED2
.text:01001DCD
.text:01001DD3                 cmp     eax, 1FEh
.text:01001DD8                 jz      loc_1001EC8

Use o menu de contexto ou atalho de teclado 'H' para valores decimais de exibição e você pode ver o nosso salto

.text:01001DBC HandleWM_COMMAND:                       ; CODE XREF: mainWndProc+197j
.text:01001DBC                 movzx   eax, word ptr [ebp+wParam]
.text:01001DC0                 mov     ecx, 528
.text:01001DC5                 cmp     eax, ecx
.text:01001DC7                 jg      loc_1001EDC
.text:01001DC7
.text:01001DCD                 jz      loc_1001ED2
.text:01001DCD
.text:01001DD3                 cmp     eax, 510
.text:01001DD8                 jz      loc_1001EC8 ; here is our jump

Isso leva a pedaço código que chama alguns proc e sai wndProc.

.text:01001EC8 loc_1001EC8:                            ; CODE XREF: mainWndProc+20Fj
.text:01001EC8                 call    sub_100367A     ; startNewGame ?
.text:01001EC8
.text:01001ECD                 jmp     callDefAndExit  ; default

é que a função que inicia novo jogo? Descobrir isso na última parte! Fique atento.

Parte 3 de 3

Vamos dar uma olhada na primeira parte dessa função

.text:0100367A sub_100367A     proc near               ; CODE XREF: sub_100140C+CAp
.text:0100367A                                         ; sub_1001B49+33j ...
.text:0100367A                 mov     eax, dword_10056AC
.text:0100367F                 mov     ecx, uValue
.text:01003685                 push    ebx
.text:01003686                 push    esi
.text:01003687                 push    edi
.text:01003688                 xor     edi, edi
.text:0100368A                 cmp     eax, dword_1005334
.text:01003690                 mov     dword_1005164, edi
.text:01003696                 jnz     short loc_10036A4
.text:01003696
.text:01003698                 cmp     ecx, dword_1005338
.text:0100369E                 jnz     short loc_10036A4

Existem dois valores (dword_10056AC, uValue) ler em registradores EAX e ecx e comparados com outros dois valores (dword_1005164, dword_1005338).

Dê uma olhada em valores reais usando WinDBG ( 'pb 01003696'; no break 'p eax; p ecx') - que parecia dimensões campo minado para mim. Jogando com o tamanho do campo minado costume mostrou que primeiro par das novas dimensões e segunda - dimensões atuais. definir novos nomes do let.

.text:0100367A startNewGame    proc near               ; CODE XREF: handleButtonPress+CAp
.text:0100367A                                         ; sub_1001B49+33j ...
.text:0100367A                 mov     eax, newMineFieldWidth
.text:0100367F                 mov     ecx, newMineFieldHeight
.text:01003685                 push    ebx
.text:01003686                 push    esi
.text:01003687                 push    edi
.text:01003688                 xor     edi, edi
.text:0100368A                 cmp     eax, currentMineFieldWidth
.text:01003690                 mov     dword_1005164, edi
.text:01003696                 jnz     short loc_10036A4
.text:01003696
.text:01003698                 cmp     ecx, currentMineFieldHeight
.text:0100369E                 jnz     short loc_10036A4

Um pouco mais tarde, novos valores atuais de substituição e de sub-rotina é chamada

.text:010036A7                 mov     currentMineFieldWidth, eax
.text:010036AC                 mov     currentMineFieldHeight, ecx
.text:010036B2                 call    sub_1002ED5

E quando eu vi

.text:01002ED5 sub_1002ED5     proc near               ; CODE XREF: sub_1002B14:loc_1002B1Ep
.text:01002ED5                                         ; sub_100367A+38p
.text:01002ED5                 mov     eax, 360h
.text:01002ED5
.text:01002EDA
.text:01002EDA loc_1002EDA:                            ; CODE XREF: sub_1002ED5+Dj
.text:01002EDA                 dec     eax
.text:01002EDB                 mov     byte ptr dword_1005340[eax], 0Fh
.text:01002EE2                 jnz     short loc_1002EDA

Eu estava completamente certo de que eu achei variedade campo minado. Causa de ciclo que inits 360h bytes de comprimento de matriz (dword_1005340) com 0xF.

Por 360h = 864? Existem algumas pistas abaixo dessa linha leva 32 bytes e 864 pode ser dividida por 32, de modo matriz pode conter 27 * 32 células (embora UI permite max campo 24 * 30, existe um estofo byte em torno de matriz para as fronteiras).

A seguir código gera top campo minado e bordas inferiores (0x10 byte). Eu espero que você pode ver iteração do loop, em que confusão;) eu tive que usar papel e caneta

.text:01002EE4                 mov     ecx, currentMineFieldWidth
.text:01002EEA                 mov     edx, currentMineFieldHeight
.text:01002EF0                 lea     eax, [ecx+2]
.text:01002EF3                 test    eax, eax
.text:01002EF5                 push    esi
.text:01002EF6                 jz      short loc_1002F11    ; 
.text:01002EF6
.text:01002EF8                 mov     esi, edx
.text:01002EFA                 shl     esi, 5
.text:01002EFD                 lea     esi, dword_1005360[esi]
.text:01002EFD
.text:01002F03 draws top and bottom borders
.text:01002F03 
.text:01002F03 loc_1002F03:                            ; CODE XREF: sub_1002ED5+3Aj
.text:01002F03                 dec     eax
.text:01002F04                 mov     byte ptr MineField?[eax], 10h ; top border
.text:01002F0B                 mov     byte ptr [esi+eax], 10h       ; bottom border
.text:01002F0F                 jnz     short loc_1002F03
.text:01002F0F
.text:01002F11
.text:01002F11 loc_1002F11:                            ; CODE XREF: sub_1002ED5+21j
.text:01002F11                 lea     esi, [edx+2]
.text:01002F14                 test    esi, esi
.text:01002F16                 jz      short loc_1002F39

E o resto da sub-rotina empates esquerdo e direito bordas

.text:01002F18                 mov     eax, esi
.text:01002F1A                 shl     eax, 5
.text:01002F1D                 lea     edx, MineField?[eax]
.text:01002F23                 lea     eax, (MineField?+1)[eax+ecx]
.text:01002F23
.text:01002F2A
.text:01002F2A loc_1002F2A:                            ; CODE XREF: sub_1002ED5+62j
.text:01002F2A                 sub     edx, 20h
.text:01002F2D                 sub     eax, 20h
.text:01002F30                 dec     esi
.text:01002F31                 mov     byte ptr [edx], 10h
.text:01002F34                 mov     byte ptr [eax], 10h
.text:01002F37                 jnz     short loc_1002F2A
.text:01002F37
.text:01002F39
.text:01002F39 loc_1002F39:                            ; CODE XREF: sub_1002ED5+41j
.text:01002F39                 pop     esi
.text:01002F3A                 retn

Smart uso de comandos WINDBG pode fornecê-lo arrefecer despejo campo minado (tamanho personalizado 9x9). Confira as fronteiras!

0:000> db /c 20 01005340 L360
01005340  10 10 10 10 10 10 10 10-10 10 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f  ................................
01005360  10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f  ................................
01005380  10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f  ................................
010053a0  10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f  ................................
010053c0  10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f  ................................
010053e0  10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f  ................................
01005400  10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f  ................................
01005420  10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f  ................................
01005440  10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f  ................................
01005460  10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f  ................................
01005480  10 10 10 10 10 10 10 10-10 10 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f  ................................
010054a0  0f 0f 0f 0f 0f 0f 0f 0f-0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f  ................................
010054c0  0f 0f 0f 0f 0f 0f 0f 0f-0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f  ................................
010054e0  0f 0f 0f 0f 0f 0f 0f 0f-0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f  ................................

Hmm, parece que eu vou precisar de outro post para fechar o tópico

Outras dicas

Parece que você está tentando desmontar a fonte, mas o que você precisa fazer é olhar para o espaço de memória do programa em execução. O editor hex HxD tem um recurso que permite exatamente isso.

http://www.freeimagehosting.net/uploads/fcc1991162.png

Uma vez que você está no espaço de memória, é uma questão de tomar instantâneos da memória enquanto você mexer com a placa. Isolar o que muda versus o que não acontece. Quando você acha que tem uma alça sobre onde as mentiras de estrutura de dados na memória hex, tente editá-lo enquanto ele está na memória e ver se a placa muda como resultado.

Não

O processo que você deseja é diferente de construir um 'treinador' para um jogo de vídeo. Aqueles são geralmente baseados em encontrar onde valores como a saúde e munição viva na memória e transformá-las em tempo real. Você pode ser capaz de encontrar alguns bons tutoriais sobre como construir formadores de jogo.

Confira este artigo projeto de código, é um pouco mais em profundidade do que o post que você mencionou.

http://www.codeproject.com/KB/trace/minememoryreader.aspx

Editar

E este artigo, embora não de caça-minas diretamente, dá-lhe um bom guia passo a passo sobre a caça através da memória usando WinDbg:

http://www.codingthewheel.com/archives/extracting- oculto-text-com-windbg

Editar 2

Mais uma vez, não se trata de caça-minas, mas tem definitivamente me deu algumas pistas de reflexão para o meu depuração de memória, há uma riqueza de tutoriais aqui:

http://memoryhacking.com/forums/index.php

Além disso, o download CheatEngine (mencionado por Nick D.) e trabalhar com o tutorial vem com ele.

'Em WinDbg posso definir pontos de interrupção, mas é difícil para mim imaginar a que ponto para definir um ponto de interrupção e, o local de memória. Da mesma forma, quando Eu vejo o código estático em IDA Pro, eu sou não tenho certeza onde começar mesmo para encontrar a função ou estrutura de dados que representa o campo de minas. "

Exatamente!
Bem, você pode olhar para rotinas como aleatório () que será chamado durante a construção da tabela de minas. Este livro me ajudou muito quando eu estava experimentando com engenharia reversa. :)

Em geral, bons lugares para definir pontos de quebra são chamadas para caixas de mensagens, chamadas para reproduzir um som, temporizadores e outras rotinas API Win32.
BTW, eu estou a digitalização de caça-minas agora com OllyDbg .

Update: nemo me lembrou uma grande ferramenta, fraude motor por Eric "Dark Byte" Heijnen.
Cheat Engine (CE) é uma grande ferramenta para assistir e modificar outros processos espaço de memória. Para além de que básico instalações, CE tem mais recursos especiais, como a visualização da memória desmontada de um processo e injetar código em outros processos.
(O real valor desse projeto é que você pode fazer o download do código-fonte -Delphi- e ver como esses mecanismos foram implementados - Eu fiz isso há muitos anos: o)

Um artigo muito bom sobre este mesmo assunto podem ser encontradas em Uninformed . Abrange reverter Minesweeper (como uma introdução à engenharia reversa Win32 Apps) em muito grande detalhe e é tudo em torno de uma muito grande recurso.

Este site pode ser mais útil:

http://www.subversity.net/reversing/hacking-minesweeper

A forma geral para ir sobre fazer isto é:

  1. De alguma forma obter o código-fonte.
  2. Desmonte e esperança sobra símbolos podem ajudá-lo.
  3. Adivinha o tipo de dados e tentar manipulá-lo e usar um scanner de memória para limitar as possibilidades.

Em resposta a recompensa

Bem, em segunda leitura, ele aparece como se você queria um guia sobre como usar um depurador como WinDBG, em vez da pergunta habitual de como a engenharia inversa. Eu já mostrei o site que você diz aos valores que você precisa para procurar, então a questão é, como você procurar por ele?

Eu estou usando o bloco de notas, neste exemplo, porque eu não tenho Minesweeper instalado. Mas a idéia é a mesma.

text alt

Você digita

s <options> <memory start> <memory end> <pattern>

Press "?" E, em seguida, "s" para ver a ajuda.

Depois de encontrar o padrão de memória que você quiser, você pode, em seguida, pressione ALT + 5 para abrir o visualizador de memória para uma exibição agradável.

text alt

WinDBG leva algum tempo para se acostumar, mas é tão bom quanto qualquer outro depurador lá fora.

Um bom ponto para começar o rastreio no depurador seria no mouse para cima. Então, encontrar o procedimento janela principal (eu acho que ferramentas como spyxx pode inspecionar propriedades janelas e endereço de manipulador de eventos é um deles). Quebre a ele e descobrir onde ele lida com eventos de mouse -. Haverá um interruptor, se você pode reconhecê-lo em assembler (olhada valor de WM_XXX para mouse em windows.h)

Coloque um ponto de interrupção lá e começar a pisar no. Em algum lugar entre o tempo que você lançou botão do mouse e tela sendo atualizados a victum irá acessar a estrutura de dados que você está procurando.

Seja paciente, tente identificar o que está sendo feito a qualquer momento, mas não se incomodam olhar muito profundamente no código suspeito de ser desinteressante para o seu objetivo atual. Pode levar várias corridas em depurador para pregá-lo para baixo.

Conhecimento de aplicações Win32 normais de fluxo de trabalho também ajuda.

As minas irá provavelmente ser armazenados em algum tipo de matriz bidimensional. Isto significa que ou é uma matriz de ponteiros ou uma única matriz estilo C de booleanos.

Sempre que o formulário recebe um evento de mouse para cima esta estrutura de dados é referenciado. O índice será calculado utilizando o rato de coordenadas, provavelmente usando divisão inteira. Isso significa que você provavelmente deve procurar um cmp ou uma instrução semelhante, onde um dos operandos é calculado usando um deslocamento e x, onde x é o resultado de um cálculo que envolve divisão inteira. O deslocamento irá então ser o apontador para o início da estrutura de dados.

É bastante razoável supor que as informações sobre minas está colocado para fora de forma contígua na memória, pelo menos para as linhas (ou seja, é um 2D matriz, ou um array-of-matrizes). Assim, I tentar abrir várias células adjacentes na mesma fileira, fazendo de estado da memória do processo como eu ir, e, em seguida, dif-los e olhar por quaisquer alterações de repetição na mesma região de memória (isto é, um byte alterados na primeira etapa, a próxima byte alterado para exatamente o mesmo valor na próxima etapa, etc).

Há também possibilidade de que é uma matriz de bits embalado (3 bits por mina deve ser suficiente para gravar todos os estados possíveis - fechado / aberto, o meu / não-mine, marcada / não-sinalizados), então eu olhar para fora isso também (os padrões também seria repetível, embora mais difícil de detectar). Mas não é uma estrutura conveniente para lidar com, e eu não acho que o uso de memória era um gargalo para Campo Minado, por isso é pouco provável que este tipo de coisa seria usado.

Embora não seja estritamente "ferramenta de engenharia reversa" a, e mais de um brinquedo, mesmo um idiota como eu poderia usar, veja cheat Engine . Isso torna um pouco mais fácil de controlar o que partes da memória mudaram, quando, e ainda tem provisões para rastrear as peças de memória alterados através de ponteiros (embora você provavelmente não precisa disso). Um tutorial interativo agradável está incluído.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top