Com as API's GetWindowText, GetClassName e o parâmetro WM_GETTEXT de SendMessage é possível obter os textos de qualquer janela da API do windows, bastando ter seu handle. O handle pode ser obtido com WindowFromPoint passando-se como parâmetro a posição do mouse.
Quando você está criando um componente, property editor, component editor ou expert para o Delphi as vezes é necessário saber qual a classe de um Property Editor já existente, por exemplo, para sabermos de onde poderemos herdar para criar o nosso.
Este programa serve para 2 objetivos principais:
1) Obter os handles, nomes e classes de todas as janelas, controles e widgets em que passamos o cursor do mouse.
É especialmente útil para sabermos o nome e classe de uma janela, classe, component editor, property editor ou expert do Delphi, principalmente quando não temos acesso ao fonte ou não conhecemos nada a respeito da mesma e precisamos saber em qual DCU ou BPL compilada ela se encontra (basta pesquisar pelo nome da classe no google que você encontra a unit onde ela está).
2) Revelar ou recuperar senhas perdidas. É importante notar que esse método só recupera senhas que estão mascaradas com asteriscos ("*") mas não recupera senhas mascaradas com a bolinha preta, predominante do windows XP pra frente, graças às novas API's.
Este não é nenhum segredo hacker, na verdade esta API, e o método para obter as senhas, existem desde os primórdios do Windows, e foram muito difundidas e utilizadas até a época do Windows 98.
Onde a recuperação de senhas vai funcionar:
Todos os programas feitos em Delphi (qualquer versão) em que as senhas sejam digitadas em um Edit e nos programas feitos em VB6. Um programa que funcionará também é o Outlook 2007 (do office 2007). Vá no painel de controle e escolha alguma conta de e-mail pop3/smtp com a senha salva. Esta senha é possível de ser revelada facilmente. Não testei as outras versões.
No momento eu não sei como fazer para recuperar as senhas contidas naqueles campos apropriados para senhas (o dos bullets pretos). Se alguém quiser colaborar com essa dica por favor comente.
O sucesso na revelação da senha depende de como o edit e sua classe foram registrados, e com que parâmetros. Em muitos sistemas seria possível obter a senha apenas obtendo-se o "caption" com GetWindowText do controle em questão, já que ele é uma "janela". Em outros o controle deve estar em foco, ou deve ser clicado.
Um FAIL gigante nesse aspecto é que o Visual Studio .Net e o .Net Framework te proporcionam a possibilidade de usar o passwordchar do sistema, ou seja, os Bullets pretos, mas mesmo assim a senha é perfeitamente revelável.
Outra coisa interessante é que o edit do lazarus não revela a senha pelo "SendMessage(hWnd, WM_GETTEXT" e nem permite que o passwordchar seja modificado, mas mesmo assim revela a senha com GetWindowText.
Crie um formulário como o da figura e coloque um timer. A maior parte do código vai nesse timer.
Para usarmos a API do windows para obter respostas textuais temos 3 opções:
1 - Usar vetores de char fixos em x caracteres (usaremos 255)
2 - Usar strings normais, porém pré-setando seu tamanho com setLength para um tamanho obtido com a mensagem WM_GETTEXTLENGTH.
3 - Utilizando ponteiros para chars (pchars) não esquecendo de alocar e desalocar memória para os mesmos.
Usando vetores
unit pegatudo;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls, shellapi;
type
TfrmPegatudo = class(TForm)
Label2: TLabel;
lbclasse: TLabel;
tempo: TTimer;
lbHandle: TLabel;
Label4: TLabel;
lbJanela: TLabel;
Label5: TLabel;
lbSenha: TLabel;
Label7: TLabel;
procedure tempoTimer(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
frmPegatudo: TfrmPegatudo;
implementation
{$R *.dfm}
procedure TfrmPegatudo.tempoTimer(Sender: TObject);
var
hWnd: THandle;
CrPos: TPoint;
nomejanela,
nomeclasse,
senha: array[0..255] of Char;
begin
try
GetCursorPos(CrPos); // Identifica a posicao do mouse
hWnd := WindowFromPoint(CrPos); // Pega o Handle do controle na posição do mouse
if hwnd <> 0 then
begin
//preenche o conteúdo do vetor com char zeros
FillChar(nomejanela, 255, #0);
FillChar(nomeclasse, 255, #0);
//pega o nome da janela
GetWindowText(hWnd, NomeJanela, 255);
//pega o nome da classe
GetClassName(hWnd, nomeclasse, 255);
//manda uma mensagem para o handle da janela
//perguntando se ele possui um password char
if SendMessage(hWnd, EM_GETPASSWORDCHAR, 0, 0) <> 0 then
begin
FillChar(senha, 255, #0);
//Caso positivo manda a mensagem WM_GETTEXT
SendMessage(hWnd, WM_GETTEXT, 255, integer(@senha)); //o integer aqui faz com que o parâmetro seja passado como ponteiro em vez de vetor
lbSenha.Caption := string(senha);
//Caso positivo seta o passwordchar para #0
//o problema de fazer isso é que vai entrar uma vez só no if
SendMessage(hWnd, EM_SETPASSWORDCHAR, 0, 0);
end;
//preenche os campos
lbHandle.Caption := IntToStr(hwnd);
lbjanela.Caption := string(nomejanela);
lbclasse.Caption := string(nomeclasse);
end;
except
end;
end;
end.
Usando Strings
unit pegatudo;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls, shellapi;
type
TfrmPegatudo = class(TForm)
Label2: TLabel;
lbclasse: TLabel;
tempo: TTimer;
lbHandle: TLabel;
Label4: TLabel;
lbJanela: TLabel;
Label5: TLabel;
lbSenha: TLabel;
Label7: TLabel;
procedure tempoTimer(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
frmPegatudo: TfrmPegatudo;
implementation
{$R *.dfm}
procedure TfrmPegatudo.tempoTimer(Sender: TObject);
var
hWnd: THandle;
CrPos: TPoint;
nomejanela,
nomeclasse,
senha: string;
tamJanela,
tamClasse,
tamSenha: integer;
begin
try
GetCursorPos(CrPos); // Identifica a posicao do mouse
hWnd := WindowFromPoint(CrPos); // Pega o Handle do controle na posição do mouse
if hwnd <> 0 then
begin
//captura o tamanho dos elementos
tamJanela := GetWindowTextLength(hwnd) + SizeOf(Char);
tamClasse := 256; //o resultado de GetClassName traz um integer com
//o número de caracteres copiados. Se for maior que 255 a string ou
//ponteiro pode ser realocado/redimensionado com setsize/malloc e
//pode ser usado GetClassName novamente para pegar a string completa
//caso ela tenha vindo truncada.
//o mesmo pode ser feito com GetWindowText, mas nesse caso a
//GetWindowTextLength nos ajuda a obter esse tamanho
//só é trazido o número de caracteres sem contar o terminator null #0
SetLength(nomejanela, tamJanela);
SetLength(nomeclasse, tamClasse);
//preenche o conteúdo do vetor com char zeros
FillChar((@nomejanela[1])^, tamJanela, #0);
FillChar((@nomeclasse[1])^, tamClasse, #0);
//pega o nome da janela
GetWindowText(hWnd, pchar(integer(NomeJanela)), tamJanela);
//pega o nome da classe
GetClassName(hWnd, pchar(integer(nomeclasse)), tamClasse);
//manda uma mensagem para o handle da janela
//perguntando se ele possui um password char
if SendMessage(hWnd, EM_GETPASSWORDCHAR, 0, 0) <> 0 then
begin
tamSenha := SendMessage(hwnd, WM_GETTEXTLENGTH, 0, 0)+ SizeOf(Char);
SetLength(senha, tamSenha);
FillChar((@senha[1])^, tamSenha, #0);
//Caso positivo manda a mensagem WM_GETTEXT
SendMessage(hWnd, WM_GETTEXT, tamSenha, integer(@senha[1])); //o integer aqui faz com que o parâmetro seja passado como ponteiro em vez de vetor
lbSenha.Caption := senha;
//seta o passwordchar para #0 e
SendMessage(hWnd, EM_SETPASSWORDCHAR, 0, 0);
end;
//preenche os campos
lbHandle.Caption := IntToStr(hwnd);
lbjanela.Caption := nomejanela;
lbclasse.Caption := nomeclasse;
end;
except
end;
end;
end.
Veja que SendMessage(hWnd, EM_SETPASSWORDCHAR, 0, 0); faz com que o edit que era do tipo password deixe de ser, e o password aparecerá desmascarado no edit.
As duas versões do código, bem como programinhas cobaia em Delphi, C# e Lazarus podem ser baixados
aqui ou na
minha página de download de exemplos.
Have Fun ;)
Ola obtenho o seguinte erro:
ResponderExcluirPegaSenhaLaz.lpr(16,4) Fatal: Cannot open include file "PegaSenhaLaz.lrs"
Está faltando esse arquivo no projeto?
Esse código foi escrito em 2011, para windows XP. Era outra versão do Lazarus também. Provavelmente não funciona hoje em dia com o windows moderno. Mas se quiser tentar, crie um projeto do zero e cole esse código em um projeto novo, em vez de baixar esses sources.
Excluir