6 maneiras de fazer a mesma coisa, o que é considerado boas práticas?

As vezes tem tantas maneiras diferentes de fazer o mesmo código que nós ficamos na dúvida quanto a qual maneira usar. O que seria considerado "boa prática" pela comunidade e o que sua equipe entenderia melhor. Suponhamos que você esteja trabalhando dentro de um método de um Domain Service chamado UmDomainServiceChique(objetoDoDominio) que será chamado por uma API. Você tem uma regra de negócio chique para ser verificada que por enquanto chamarei de VerificaMinhaRegraChiqueComplexa(). Você chama UmDomainServiceChique(objetoDoDominio) e caso VerificaMinhaRegraChiqueComplexa() retorne true você vai querer que UmDomainServiceChique faça o que tem que fazer e a api retornar Ok 200, caso contrário você quer que a API responda um erro qualquer, tipo BadRequest, e retornar uma mensagem dizendo que VerificaMinhaRegraChiqueComplexa deu ruim. Eu vejo 6 maneiras de fazer isso, gostaria de saber a opinião de outrs devs sobre qual seria a maneira menos gambiarr

Api hooking para mudar o usuário logado

Já está nas bancas a revista Clube Delphi 127 com meu primeiro artigo sobre a madShi Collection. Neste artigo eu explico o básico sobre API Hooking.

Neste post falarei sobre um exemplo que não se encontra no artigo, que é o hooking da API GetUserName.
Os motivos que levam a hookar essa API podem ser variados, e todos eles nada éticos a meu ver. Você pode desde tentar enganar um produto registrado para um usuário acessando-o como outro usuário ou simplesmente para tapear um usuário administrador, que quando olhar quem está logado verá um nome diferente (supondo que isso funcione, não testei).

A idéia é que dá para mudar a resposta que outros programas recebem quando perguntam quem é o usuário logado. Para isso é necessário conhecer quais são as api's que fazem isso e como interceptá-las.

O código dessa postagem mostra como usar a madCodeHook para interceptar a api GetUserName da api do windows.

Primeiro de tudo criei um programa que mostra o nome do usuário corrente:


function NomeUsuario: string;
var
  I: DWord;
begin
  I := 255;
  SetLength(Result, I);
  Windows.GetUserName(PChar(Result), I);
  Result := string(PChar(Result));
end;



procedure TForm2.btTestarClick(Sender: TObject);

begin
  Edit1.Text := NomeUsuario;
end;



Esse programa simplesmente mostra o usuário logado. Depois de injetada a DLL que faz o hook a chamada a GetUserName terá seu resultado mudado.
É preciso salientar que existe outra api chamada GetUserNameEx que não está mapeada na unit windows.pas e que aceita mais parâmetros, e devolve mais resultados.

Interceptar essas duas API's é certeza de que mudará os resultados às suas relativas chamadas. Não é garantia nenhuma de que será possível abrir um arquivo para o qual seu usuário atual não tem autorização, mas não custa nada tentar.

Como pôde ser visto nos artigos que escrevi para a Revista Clube Delphi, eis o código da dll a ser injetada.

Essa dll intercepta apenas a função GetUserName, deixo a cargo do leitor a GetUserNamneEx, que é mais complexa. Num post futuro trataremos da GetUserNameEx. Deixo apenas o esqueleto para quem quiser se aventurar.

Lembre-se de que se estiver usando a versão trial/demo da madCollectionHook deverá manter mchEvaluation rodando para que o hooking funcione.

library hook;

uses
  SysUtils,
  windows,
  Classes,
  madcodehook;

{$R *.res}


const
  USUORIGINAL =  'vitorrubio';    //       vitorrubio --> meu user
  USUTROCA = 'Administrador';       //       Administrador--> quem quero ser




var
  GetUserNameWNext:  function (lpBuffer: PWideChar; var nSize: DWORD): BOOL; stdcall;
  GetUserNameANext:  function (lpBuffer: PAnsiChar; var nSize: DWORD): BOOL; stdcall;


function GetUserNameWCallback (lpBuffer: PWideChar; var nSize: DWORD): BOOL; stdcall;
begin

  Result := GetUserNameWNext(lpBuffer, nSize);
  if (trim(string(lpBuffer)) = USUORIGINAL) then
  begin
    StrCopy(lpBuffer, USUTROCA);
    nSize := Length(USUTROCA);
  end;

end;

function GetUserNameACallback (lpBuffer: PAnsiChar; var nSize: DWORD): BOOL; stdcall;
begin

  Result := GetUserNameANext(lpBuffer, nSize);
  if (trim(AnsiString(lpBuffer)) = AnsiString(USUORIGINAL)) then
  begin
    StrCopy(lpBuffer, USUTROCA);
    nSize := Length(USUTROCA);
  end;

end;

begin
  HookAPI('advapi32.dll', 'GetUserNameW',  @GetUserNameWCallback, @GetUserNameWNext);
  HookAPI('advapi32.dll', 'GetUserNameA',  @GetUserNameACallback, @GetUserNameANext);
end.


Agora o código para injetar, desinjetar e testar a dll:

procedure TForm1.btInjetarClick(Sender: TObject);
begin
  InjectLibrary(ALL_SESSIONS or SYSTEM_PROCESSES, 'hook.dll');
end;

procedure TForm1.btTestarClick(Sender: TObject);
begin
  Edit1.Text := NomeUsuario;
end;

procedure TForm1.btDesinjetarClick(Sender: TObject);
begin
  UninjectLibrary(ALL_SESSIONS or SYSTEM_PROCESSES, 'hook.dll');
end;

Crie uma form com 3 botões e um edit e teste. Lembre-se de todas as medidas de segurança necessárias para se trabalhar com API hooking e lembre-se que toda a api do windows se invoca com stdcall.

Coloque a dll e o testador em um mesmo project group para facilitar.

É importante salientar que qualquer processo que use a GetUserNameEx para identificar o usuário não sofrerá nenhum efeito desse hooking. Além disso o windows tem outras formas, de baixo nível, para descobrir o usuário logado.

Have fun :)

Comentários

Postagens mais visitadas deste blog

Busca de CEP com o Lazarus - Parte 1 - UrlEncode

Botão Add This para adicionar seu post em qualquer rede

Uso de memória no SQL Server