Ver Mensaje Individual
  #14  
Antiguo 28-08-2015
Avatar de escafandra
[escafandra] escafandra is offline
Miembro Premium
 
Registrado: nov 2007
Posts: 2.197
Reputación: 20
escafandra Tiene un aura espectacularescafandra Tiene un aura espectacular
Vamos a dar un empujoncito al tema. He escrito una función un poco a lo bruto para cambiar una cadena en un proceso. He de aclarar que está escrito en delphi7, que se compila para 32bits, esto quiere decir que no se pueden atacar de esta forma procesos de 64bits. Lo he probado en winXP y en Win10:

Código Delphi [-]
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, TLHelp32;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Edit1: TEdit;
    Label1: TLabel;
    Edit2: TEdit;
    Label2: TLabel;
    Label3: TLabel;
    Edit3: TEdit;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

function  _wcsnicmp(wstr1, wstr2: PWCHAR; Size: integer): Integer; cdecl external 'crtdll';
function  wcslen(wstr: PWCHAR): Integer; cdecl external 'crtdll';


var
  Form1: TForm1;

implementation

{$R *.dfm}

//---------------------------------------------------------------------------
function EnablePrivilege(name: String; Enable: boolean = true): boolean;
var
  hToken: Cardinal;
  priv: TOKEN_PRIVILEGES;
begin
  priv.PrivilegeCount:= 1;
  priv.Privileges[0].Attributes:= 0;
  if Enable then priv.Privileges[0].Attributes:= SE_PRIVILEGE_ENABLED;
  LookupPrivilegeValue(nil, PCHAR(name), priv.Privileges[0].Luid);
  OpenProcessToken(GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES, hToken);
  AdjustTokenPrivileges (hToken, FALSE, priv, sizeof(priv), nil, PDWORD(nil)^);
  Result:= (GetLastError = ERROR_SUCCESS);
  CloseHandle (hToken);
end;

//---------------------------------------------------------------------------
function RemoteReplaceString(PID: DWORD; Str, NewStr: PWCHAR): BOOL;
const
  nBytes = $16000;
var
  hProc: THANDLE;
  n, i, T, Len, nBytesRead: DWORD;
  Buffer, RemoteAddr: PBYTE;
  bi: MEMORY_BASIC_INFORMATION;
begin
  Result:= false;
  hProc:= OpenProcess(PROCESS_ALL_ACCESS, false, PID);
  Len:= wcslen(Str) * sizeof(WCHAR);
  GetMem(Buffer, nBytes);

  EnablePrivilege('SeDebugPrivilege');

  // Escaneamos la memoria del proceso en busca de la cadena
  for n:= 0 to $1000 do
  begin
     RemoteAddr:= PBYTE(n*nBytes-Len);
     ReadProcessMemory(hProc, RemoteAddr, Buffer, nBytes, nBytesRead);
     if nBytesRead > 0 then
     begin
       //Le resto el modulo de la división para no perderme cadenas partidas
       T:= nBytesRead - (nBytesRead mod wcslen(Str));
       i:= 0;
       while i <= T do
       begin
         // Busco la cadena en el buffer "no case sensitive"
         if _wcsnicmp(PWCHAR(DWORD(Buffer)+i), Str, wcslen(Str)) = 0 then
         begin
            // Si la encuentro la escribo en el proceso remoto
            if WriteProcessMemory(hProc, pointer(DWORD(RemoteAddr) + i), NewStr, Len, nBytesRead) then
              // si pude escribir incremento el índice para seguir buscando
              i:= i + wcslen(Str);
         end;
         inc(i);
       end;
     end;
   end;
   FreeMem(Buffer);
   CloseHandle(hProc);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  proc: TProcessEntry32;
  hSysSnapshot: THandle;
begin
  proc.dwSize := SizeOf(TProcessEntry32);
  hSysSnapshot:= CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  if (hSysSnapshot <> INVALID_HANDLE_VALUE) and Process32First(hSysSnapshot, proc) then
  begin
    repeat
      if SameText(String(proc.szExeFile), Edit1.Text) then
        RemoteReplaceString(proc.th32ProcessID, PWCHAR(WideString(Edit2.Text)), PWCHAR(WideString(Edit3.Text)));
    until not (Process32Next(hSysSnapshot, proc));
  end;
  CloseHandle(hSysSnapshot);
end;

end.


He de comentar lo siguiente:

1- Las cadenas de un proceso en memoria deben tratarse como UNICODE
2- He usado funciones "C" de la librería crtdll.dll que trae Windows como parte del S.O. para faciñitar la búsquede de cadenas a bajo nivel
- wcslen devuelve el número de caracteres de una cadena tipo WCHAR
- _wcsnicmp compara una cadena WCHAR con otra en una longitud máxima dada y sin ser sensible a mayúsculas/minúsculas
3- Un código para 32bits no puede leer la memoria de un proceso 64 bits sin más, se precisa un driver o trucos especiales, esto es debido a la incompatibilidad de los punteros que definen el rango de direcciones que son capaces de direccionar.
4- No se puede sustituir una cadena por otra de mayor longitud.

Espero aclarar alguna duda a deliriun.


Saludos.

Última edición por escafandra fecha: 09-03-2020 a las 08:00:24.
Responder Con Cita