Как вызвать «dll unload» без сбоев целевого процесса? (я не хочу использовать API-крючок) - PullRequest
0 голосов
/ 18 января 2019

Я хочу выгрузить определенные dll моего исполняемого файла без необходимости использовать технику hook api для предотвращения внедрения.

Код ниже был тем, что я пробовал в прошлый раз, но мой исполняемый файл вылетает при выполнении этой строки:

if pfnDllMain(ModuleHandle, DLL_PROCESS_DETACH, 1) then

Как починить?

Полный код:

program BlockDll;

{$APPTYPE CONSOLE}
{$WARN SYMBOL_PLATFORM OFF}
{$R *.res}

uses
  Windows,
  TlHelp32,
  SysUtils;

var
  sArray: array [0 .. 0] of string = (
    'Project1.dll'
  );

function GetAddressOfEntryPoint(hmod: DWORD): pointer;
var
  pidh: PImageDosHeader;
  pinth: PImageNtHeaders;
  pvEntry: pointer;
begin
  pidh := PImageDosHeader(hmod);
  pinth := PImageNtHeaders(PBYTE(hmod) + pidh^._lfanew);
  pvEntry := PBYTE(hmod) + pinth.OptionalHeader.AddressOfEntryPoint;
  Result := pvEntry;
end;

function GetDllFileName(HMODULE: Cardinal): String;
var
  Res: DWORD;
begin
  SetLength(Result, 32767);
  Res := GetModuleFileName(HMODULE, PWideChar(Result), Length(Result));
  if Res = 0 then
  begin
    Writeln('GetModuleFileNameW fails with error: ' + IntToStr(GetLastError));
    Exit;
  end;
  SetLength(Result, Res);
end;

function GetModuleHandleExW(Flags: DWORD; ModuleNameOrAddr: PWideChar;
  var ModuleHandle: HMODULE): BOOL; stdcall;
  external kernel32 name 'GetModuleHandleExW';

procedure unloadDll(moduleName: string);
type
  fnDllMain = function(hinstDLL: Cardinal; fdwReason: DWORD;
    lpvReserved: Cardinal): Boolean; stdcall;
const
  GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT = 2;
var
  Handle: THandle;
  ModuleEntry: TModuleEntry32;
  ModuleHandle: HMODULE;
  pfnDllMain: fnDllMain;
begin
  Handle := CreateToolHelp32SnapShot(TH32CS_SNAPMODULE, 0);
  Win32Check(Handle <> INVALID_HANDLE_VALUE);

  try
    ModuleEntry.dwSize := Sizeof(ModuleEntry);
    Win32Check(Module32First(Handle, ModuleEntry));

    repeat

      if (ModuleEntry.szModule = moduleName) then
      begin

        if GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
          PWideChar(moduleName), ModuleHandle) then
        begin
          @pfnDllMain := GetAddressOfEntryPoint(ModuleHandle);

          if Assigned(pfnDllMain) then
          begin
            if pfnDllMain(ModuleHandle, DLL_PROCESS_DETACH, 1) then
              Writeln('unloadDll success! - ' + GetDllFileName(ModuleHandle));
          end;
        end;

      end;

    until not Module32Next(Handle, ModuleEntry);
  finally
    CloseHandle(Handle);
  end;
end;

function AntiDllInjection(param: pointer): Integer;
var
  i: Integer;
begin
  while (True) do
  begin
    for i := Low(sArray) to High(sArray) do
      unloadDll(sArray[i]);
    Sleep(1000);
  end;
  Result := 0;
end;

var
  id: LongWord;

begin
  try
    BeginThread(nil, 0, AntiDllInjection, nil, 0, id);
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;

end.

1 Ответ

0 голосов
/ 18 января 2019

ОК, я уже видел код, в котором автор записывает случайные данные в точку входа введенной dll. был код для отладки целевого процесса и DLL был введен в эту цель. Выгрузка была сделана в событии load_dll_debug_event .

Тогда такой подход записи случайных данных в точку входа введенного модуля или в ваш базовый адрес кажется решением, более приемлемым для моего вопроса, это может привести к выгрузке dll без сбоя процесса.

И работает, но при этом используется функция CreateProcess() для отладки цели (жертва процесса).

Я ищу альтернативу, чтобы выполнить ту же задачу без необходимости в 2 исполняемых файлах, но если ее не существует, то считаю это окончательным решением до этого момента.

program SpecialLauncher;

// MinDbg的Delphi版本源代码
// http://m.newsmth.net/article/Delphi/777

//program EventTester;
//{$APPTYPE CONSOLE}
{uses
  Windows, SysUtils;
begin
  try
    raise Exception.Create('This is a test');
  except
    On E: Exception do
      OutputDebugString(PChar(E.Message));
  end;
end.}

{$APPTYPE CONSOLE}
{$WARN SYMBOL_PLATFORM OFF}

uses
  Windows,
  Psapi,
  SysUtils;

type
 NTStatus = cardinal;

 PIO_STATUS_BLOCK = ^IO_STATUS_BLOCK;

  IO_STATUS_BLOCK = packed record
    Status: NTStatus;
    Information: dword;
  end;

  PFILE_NAME_INFORMATION = ^FILE_NAME_INFORMATION;

  FILE_NAME_INFORMATION = packed record
    FileNameLength: ULONG;
    FileName: array [0 .. MAX_PATH - 1] of WideChar;
  end;

function NtQueryInformationFile(FileHandle: THandle;
  IoStatusBlock: PIO_STATUS_BLOCK; FileInformation: pointer; Length: dword;
  FileInformationClass: dword): NTStatus; stdcall; external 'ntdll.dll';

const
  Values : Array[0..4] of byte = ($C2,$00,$00,$90,$90);

var
  bSeenInitialBP: Boolean;
  hProcess: THandle;

function GetFileNameFromHandle(const hFile: THandle): string;
var
  IO_STATUSBLOCK: IO_STATUS_BLOCK;
  FileNameInfo: FILE_NAME_INFORMATION;
  szFile: String;
begin
  FillChar(FileNameInfo.FileName, SizeOf(FileNameInfo.FileName), 0);
  NtQueryInformationFile(hFile, @IO_STATUSBLOCK, @FileNameInfo, 500, 9);
  szFile := WideCharToString(FileNameInfo.FileName);
  Result := ExtractFileName(szFile);
end;

{function GetFileNameFromHandle(hFile: cardinal): String;
var
  hFileMap: cardinal;
  pMem: pointer;
  FilePath: array [0 .. MAX_PATH - 1] of Char;
  sFilePath: String;
  sFileName: String;
begin
  Result := '';
  try
    hFileMap := CreateFileMapping(hFile, NIL, PAGE_READONLY, 0, 0, NIL);
    if hFileMap <> 0 then
    begin
      pMem := MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 1);
      if pMem <> NIL then
      begin
        if GetMappedFileName(GetCurrentProcess(), pMem, @FilePath,
          SizeOf(FilePath)) <> 0 then
        begin
          sFilePath := StrPas(FilePath);
          sFileName := ExtractFileName(sFilePath);
          Result := sFilePath;
        end
        else
          Exit;
      end
      else
        Exit;
    end
    else
      Exit;
  finally
    UnMapViewOfFile(pMem);
    CloseHandle(hFileMap);
  end;

end;}

function GetDllEntryPoint(hFile: DWORD; hModule: pointer): pointer;
var
  hMapFile, dwFSizeLow, dwFSizeHight: DWORD;
  pMemory, DllEntryPoint: pointer;
  idh: PImageDosHeader;
  inh: PImageNtHeaders;
begin
  DllEntryPoint := nil;
  pMemory := nil;
  dwFSizeHight := 0;
  dwFSizeLow := GetFileSize(hFile, @dwFSizeHight);

  if ((hFile > 0) and (dwFSizeLow > 0)) then
  begin
    Writeln('');
    writeln(Format('Dll size: %d', [dwFSizeLow]));

    hMapFile := CreateFileMapping(hFile, nil, PAGE_READONLY, dwFSizeHight, dwFSizeLow, nil);

    Writeln(Format('Error: 0x%.08x', [GetLastError]));

    pMemory := MapViewOfFile(hMapFile, FILE_MAP_READ,
      0, 0, 0);

    if (Assigned(pMemory)) then
    begin

      idh := pointer(pMemory);
      inh := pointer(DWORD(idh) + idh^._lfanew);
      DllEntryPoint := PBYTE(hModule) + inh^.OptionalHeader.AddressOfEntryPoint;
    end;

    UnmapViewOfFile(pMemory);
    CloseHandle(hMapFile);
    // CloseHandle(hFile);
  end;
  Result := DllEntryPoint;
end;

procedure WriteBytes(hProcess: THandle; Address: Pointer; const Buffer: array of Byte);
var
  Read: THandle;
  oldprot, tmp: DWORD;
begin
  if (VirtualProtectEx(hProcess, Address, Length(Buffer), PAGE_EXECUTE_READWRITE, @oldprot)) then
      Writeln('1 - VirtualProtectEx() successfully!');
  if (WriteProcessMemory(hProcess, Address, @Buffer, Length(Buffer), Read)) then
      Writeln('2 - WriteProcessMemory() successfully!');
  if (VirtualProtectEx(hProcess, Address, Length(Buffer), oldprot, @tmp)) then
      Writeln('3 - VirtualProtectEx() successfully!');

       Writeln('');
end;

procedure Help;
begin
  WriteLn(ExtractFileName(ParamStr(0)) + ' <program to debug> ');
end;

type
  TDebugEventHandler = function(const de: TDebugEvent): DWORD;

const
  DebugEventNames: array [EXCEPTION_DEBUG_EVENT .. RIP_EVENT]
    of string = ('EXCEPTION_DEBUG_EVENT', 'CREATE_THREAD_DEBUG_EVENT',
    'CREATE_PROCESS_DEBUG_EVENT', 'EXIT_THREAD_DEBUG_EVENT',
    'EXIT_PROCESS_DEBUG_EVENT', 'LOAD_DLL_DEBUG_EVENT',
    'UNLOAD_DLL_DEBUG_EVENT', 'OUTPUT_DEBUG_STRING_EVENT', 'RIP_EVENT');

function DefaultDebugEventHandler(const de: TDebugEvent): DWORD;
begin
  WriteLn('========================================');
  WriteLn(Format('Debug Event [%d] : %s', [de.dwDebugEventCode,
    DebugEventNames[de.dwDebugEventCode]]));
  Result := DBG_CONTINUE;
end;

function ExceptionHandler(const de: TDebugEvent): DWORD;
  procedure ShowExceptionRecord(const per: PExceptionRecord);
  var
    I: Integer;
  begin
    if Assigned(per) and not IsBadReadPtr(per, SizeOf(TExceptionRecord))
      then with per^ do
    begin
      WriteLn;
      WriteLn(Format('  ExceptionCode           : 0x%.08x', [ExceptionCode]));
      WriteLn(Format('  ExceptionFlags          : 0x%.08x', [ExceptionFlags]));
      WriteLn(Format('  ExceptionRecord         : 0x%p', [ExceptionRecord]));
      WriteLn(Format('  ExceptionAddress        : 0x%p', [ExceptionAddress]));
      WriteLn(Format('  NumberParameters        : 0x%.08x',
        [NumberParameters]));
      if NumberParameters > 0 then
        for I := 0 to NumberParameters - 1 do
          WriteLn(Format('    ExceptionInformation[%d] : 0x%.08x',
            [I, ExceptionInformation[I]]));
      ShowExceptionRecord(ExceptionRecord);
    end;
  end;

begin
  if not bSeenInitialBP then
  begin
    bSeenInitialBP := True;
    Result := DBG_CONTINUE;
  end
  else
  begin
    DefaultDebugEventHandler(de);
    with de.Exception do
    begin
      WriteLn(Format('  dwFirstChance           : 0x%.08x', [dwFirstChance]));
      ShowExceptionRecord(@ExceptionRecord);
    end;
    Result := DBG_EXCEPTION_NOT_HANDLED
  end;
end;

function CreateProcessHandler(const de: TDebugEvent): DWORD;
begin
  Result := DefaultDebugEventHandler(de);
  hProcess := de.CreateProcessInfo.hProcess;
  with de.CreateProcessInfo do
  begin
    WriteLn(Format('  hFile                   : 0x%.08x', [hFile]));
    WriteLn(Format('  hProcess                : 0x%.08x', [hProcess]));
    WriteLn(Format('  hThread                 : 0x%.08x', [hThread]));
    WriteLn(Format('  lpBaseOfImage           : 0x%p', [lpBaseOfImage]));

    WriteLn(Format('  dwDebugInfoFileOffset   : 0x%.08x',[dwDebugInfoFileOffset]));
    WriteLn(Format('  nDebugInfoSize          : 0x%.08x', [nDebugInfoSize]));
    WriteLn(Format('  lpThreadLocalBase       : 0x%p', [lpThreadLocalBase]));
    WriteLn(Format('  lpStartAddress          : 0x%p', [lpStartAddress]));
    WriteLn(Format('  lpImageName             : 0x%p', [lpImageName]));
    WriteLn(Format('  ImageName               : %s', [GetFileNameFromHandle(hFile)]));
    WriteLn(Format('  fUnicode                : 0x%.08x', [fUnicode]));

  end;
end;

function ExitProcessHandler(const de: TDebugEvent): DWORD;
begin
  Result := DefaultDebugEventHandler(de);
  with de.ExitProcess do
    WriteLn(Format('  dwExitCode              : 0x%.08x', [dwExitCode]));
end;

function CreateThreadHandler(const de: TDebugEvent): DWORD;
begin
  Result := DefaultDebugEventHandler(de);
  with de.CreateThread do
  begin
    WriteLn(Format('  hThread                 : 0x%.08x', [hThread]));
    WriteLn(Format('  lpThreadLocalBase       : 0x%p', [lpThreadLocalBase]));
    WriteLn(Format('  lpStartAddress          : 0x%p', [lpStartAddress]));
  end;
end;

function ExitThreadHandler(const de: TDebugEvent): DWORD;
begin
  Result := DefaultDebugEventHandler(de);
  with de.ExitThread do
    WriteLn(Format('  dwExitCode              : 0x%.08x', [dwExitCode]));
end;

function LoadDllHandler(const de: TDebugEvent): DWORD;
var
 DllEntryPtr: Pointer;
 DllName: string;
begin
  Result := DefaultDebugEventHandler(de);
  with de.LoadDll do
  begin
    WriteLn(Format('  hFile                   : 0x%.08x', [hFile]));
    DllName := GetFileNameFromHandle(hFile);
    WriteLn(Format('  lpBaseOfDll             : 0x%p', [lpBaseOfDll]));
    WriteLn(Format('  dwDebugInfoFileOffset   : 0x%.08x', [dwDebugInfoFileOffset]));
    WriteLn(Format('  nDebugInfoSize          : 0x%.08x', [nDebugInfoSize]));
    WriteLn(Format('  lpImageName             : 0x%p', [lpImageName]));
    WriteLn(Format('  ImageName               : %s', [DllName]));
    WriteLn(Format('  fUnicode                : 0x%.08x', [fUnicode]));

    //////////////////////////////////////////////////////////////////////////

      if ( Pos('dll01.dll', DllName) > 0) or
         ( Pos('dll02.dll', DllName) > 0) or
         ( Pos('dll03.dll', DllName) > 0) or
         ( Pos('dll04.dll', DllName) > 0) then
    begin

      DllEntryPtr := GetDllEntryPoint(hFile, lpBaseOfDll);

      if DllEntryPtr <> nil then
        WriteBytes(hProcess, DllEntryPtr, Values)
      else
        Writeln('GetDllEntryPoint() failed.');
    end;

    /////////////////////////////////////////////////////////////////////////

  end;
end;

function UnloadDllHandler(const de: TDebugEvent): DWORD;
begin
  Result := DefaultDebugEventHandler(de);
  with de.UnloadDll do
    WriteLn(Format('  lpBaseOfDll             : 0x%p', [lpBaseOfDll]));
end;

function DebugStringHandler(const de: TDebugEvent): DWORD;
var
  Buf: array [1 .. 1024] of Byte;
  dwRead: DWORD;
begin
  Result := DefaultDebugEventHandler(de);
  with de.DebugString do
  begin
    WriteLn(Format('  lpDebugStringData       : 0x%.08x', [DWORD(lpDebugStringData)]));
    WriteLn(Format('  nDebugStringLength      : 0x%.08x', [nDebugStringLength]));
    WriteLn(Format('  fUnicode                : 0x%.08x', [fUnicode]));
    if nDebugStringLength < SizeOf(Buf) then
    begin
      FillChar(Buf, SizeOf(Buf), 0);
      ReadProcessMemory(hProcess, lpDebugStringData, @Buf, SIZE_T(nDebugStringLength), SIZE_T(dwRead));
      Write('  DebugString             : ');
      if fUnicode <> 0 then
        WriteLn(WideString(PWideChar(@Buf)))
      else
        WriteLn(string(PChar(@Buf)));
    end;
  end;
end;

function RipHandler(const de: TDebugEvent): DWORD;
begin
  Result := DefaultDebugEventHandler(de);
  with de.RipInfo do
  begin
    WriteLn(Format('  dwError                 : 0x%.08x', [dwError]));
    WriteLn(Format('  dwType                  : 0x%.08x', [dwType]));
  end;
end;

const
  DebugEventHandlers: array [EXCEPTION_DEBUG_EVENT .. RIP_EVENT]
    of TDebugEventHandler = (ExceptionHandler, CreateThreadHandler,
    CreateProcessHandler, ExitThreadHandler, ExitProcessHandler, LoadDllHandler,
    UnloadDllHandler, DebugStringHandler, RipHandler);

procedure Init;
var
  si: TStartupInfo;
  pi: TProcessInformation;
begin
  bSeenInitialBP := False;
  hProcess := INVALID_HANDLE_VALUE;
  FillChar(si, SizeOf(TStartupInfo), 0);
  FillChar(pi, SizeOf(TProcessInformation), 0);
  si.cb := SizeOf(TStartupInfo);
  Win32Check(CreateProcess({nil}'c:\windows\system32\notepad.exe', {PChar(ParamStr(1)}nil{)}, nil, nil, False,
    CREATE_NEW_CONSOLE or DEBUG_ONLY_THIS_PROCESS, nil, nil, si, pi));
end;

procedure Run;
var
  de: TDebugEvent;
  bContinue: Boolean;
  dwContinueStatus: DWORD;
begin
  bContinue := True;
  while bContinue do
  begin
    bContinue := WaitForDebugEvent(de, INFINITE);
    dwContinueStatus := DebugEventHandlers[de.dwDebugEventCode](de);
    if EXIT_PROCESS_DEBUG_EVENT = de.dwDebugEventCode then
      bContinue := False;
    ContinueDebugEvent(de.dwProcessId, de.dwThreadId, dwContinueStatus);
  end;
end;

procedure Done;
begin
end;

begin
 { if ParamCount = 0 then
  begin
    Help;
    Exit;
  end; }
  Init;
  Run;
  Done;

end.
...