Oficina
Bloco de Notas com linhas numeradas
Seg 28 Mai 2007 20:28 |
- Detalhes
- Categoria: Oficina de Assembly
- Atualização: Quinta, 18 Junho 2009 11:44
- Autor: vovó Vicki
- Acessos: 23251
Vitaminar um programa existente exige um bom conhecimento da estrutura e do funcionamento de executáveis. A proposta deste tutorial, baseado no texto publicado por razzia em 19.08.97, é reforçar as noções básicas através de um exercício de re-engenharia de um velho conhecido: o Bloco de Notas do Windows.
O Bloco de Notas (Notepad), entre outras limitações, não indica números de linha - algo que seria muito útil em diversas situações. Mesmo que você não veja vantagens em adicionar o número das linhas ao programa, talvez seja interessante saber como modificar um executável sem possuir seu código fonte.
Escrevi este tutorial em 2001. Na época, a versão do bloco de notas era de 08/06/2000. Sugiro que faça o download desta versão do executável para poder acompanhar o texto. Você o encontra na seção de downloads em Informática / Programação.
O procedimento WndProc
Para determinar o código que será adicionado precisamos investigar um pouco o programa alvo. O "coração" de qualquer programa Windows é o procedimento WndProc. Este procedimento é chamado pelo Windows toda vez que o usuário interage com a janela do programa. O Windows passa alguns parâmetros para este procedimento (por exemplo, a mensagem da janela) para que o WndProc possa saber o que ocorreu e efetuar a atualização da janela.
No caso do bloco de notas, o programa principal gera uma janela filha da classe "edit", que sempre ocupa o tamanho total da janela principal. Se quisermos imprimir nosso próprio texto na janela principal, será necessário reduzir o tamanho da janela filha para que ela não cubra a área total da janela principal. Cada vez que o usuário alterar o tamanho da janela principal, o Windows chama WndProc com a mensagem WM_SIZE. O procedimento WndProc reage a este evento e ajusta o tamanho da janela filha "edit" ao novo tamanho da janela principal.
Se localizarmos o procedimento WndProc será possível avaliar como ele lida com a mensagem WM_SIZE. Entre as várias maneiras de fazer isto, a mais fácil é através da função da API RegisterClass. O bloco de notas usa a função RegisterClassExA, função que registra uma classe janela para uso subsequente em chamadas para as funções CreateWindow ou CreateWindowEx.
ATOM RegisterClassEx( CONST WNDCLASSEX *lpwcx );
O parâmetro lpwcx é um ponteiro que aponta para uma estrutura do tipo WNDCLASSEX. Esta estrutura precisa ser preenchida com os atributos de classe apropriados antes do parâmetro ser passado para a função. Caso a função seja executada com sucesso, o valor de retorno é um atom que identifica unicamente a classe que está sendo registrada. Em caso de falha, o valor de retorno é zero.
Conhecendo a função e suas características, podemos usar o W32Dasm ou o IDA para obter o bloco de código que se referente à função. No W32Dasm, após carregar o programa, clique no item de menu Functions / Imports para abrir a janela com todas as funções importadas. Localize nesta janela a função USER32.RegisterClassExA e dê um duplo clique sobre a referência para ser levado ao código correspondente:
Caso você queira testar o IDA, carregue o programa, selecione o item de menu Jump / Jump to name (ou simplesmente Ctrl+L) para obter a janela de nomes. Selecione RegisterClassExA e digite [enter]. Você será levado ao seguinte trecho de código, que é a referência na seção .idata (seção das importações) da função procurada:
.idata:0040644C extrn RegisterClassExA:dword ; DATA XREF: sub_403140+71^r
Feche a janela de nomes e dê um duplo clique sobre a referência "sub_403140+71^r". Você será levado para a seção .text no seguinte ponto:
Conhecendo a localização do WndProc, vamos analisar o código correspondente a esta chamada. No W32Dasm, selecione o item de menu Goto / Goto Code Location e indique o endereço 401C8C. No IDA, basta dar um duplo clique sobre "sub_401C8C" para ser levado à subrotina:
Na linha 401C93 o programa checa o tipo de mensagem recebida e garante que seu valor esteja entre 1 e 5. Na linha seguinte, caso o valor seja maior do que 5 (nenhuma mensagem válida), salta para 401CAC. Caso a mensagem seja 5, salta para 401DA4, caso contrário continua determinando o tipo da mensagem. As mensagens válidas estão descritas em WM_SIZE, que representa o tipo da mensagem enviada para uma janela após seu tamanho ter sido modificado.
Parâmetros | Observação>/td> | Valor | Hexa | Significado |
fwSizeType = wParam; | // flag de redimensionamento | SIZE_MAXHIDE | 1 | Mensagem enviada para todas as janelas popup quando qualquer outra é maximizada |
SIZE_MAXIMIZED | 2 | Janela foi maximizada | ||
SIZE_MAXSHOW | 3 | Mensagem enviada para todas as janelas popup quando qualquer outra tenha sido restaurada ao tamanho original. | ||
SIZE_MINIMIZED | 4 | Janela foi minimizada. | ||
SIZE_RESTORED | 5 | A janela foi redimensionada mas não minimizada ou maximizada. | ||
nWidth = LOWORD(lParam); | // largura da área cliente | |||
nHeight = HIWORD (lParam); | // altura da área cliente | |||
Valor de retorno: Se a mensagem foi processada, o valor de retorno é 0 (zero). |
De posse dessas informações, fica claro que o programa checa a validade e o valor da mensagem para decidir que caminho tomar. Nós queremos esclarecer o que é feito caso WM_SIZE seja igual a 5 (SIZE_RESTORED), ou seja, o tamanho da janela foi modificado sem que ela tenha sido maximizada ou minimizada. Para isto, precisamos rastrear o salto que o programa efetua para o endereço 401DA4. No IDA, basta um duplo clique sobre "loc_401DA4" (no W32Dasm selecione Goto):
Analisando este trecho de código, nos deparamos com uma chamada à subrotina 40121B:
Note que aparentemente o manipulador (handle) da janela filha "edit" é armazenado no endereço (virtual) de nome hWnd. Para encontrar o valor de hWnd usando o IDA, selecione o item de menu View / Open subviews / Names (Shift+F4) para obter a janela de nomes. Nesta, selecione Search / Search (Alt+T) e digite o nome do endereço (hWnd): você encontrará hWndMain = 405000 e hWnd = 405004. Anote cuidadosamente estes endereços pois ainda vamos precisar muito deles!
Também podemos verificar que, para cada mensagem WM_SIZE, a janela filha "edit" é atualizada com uma chamada para MoveWindow com o novo tamanho da janela principal.
- Anterior
- Próximo >>