Simple Firewall

posted 14 Sep 2010, 20:10 by Delphi Basics   [ updated 14 Sep 2010, 20:14 ]
This delphi source code, written by sk0r, details how to use detour hooks to pause the calling of an api whilst waiting for a user action. The firewall also features anti-debugging techniques.

Hook.dll
library Hook;

uses
  SysUtils,
  Windows,
  Winsock,
  Classes;

{$R *.res}

var o_connect: function(s: Integer; const name: sockaddr_in; namelen: Integer):Integer;stdcall;
var dwThreadID: Cardinal = 0;

function IsDebuggerPresent:LongBool;stdcall; external 'kernel32.dll';

function RunningApp:String;
var
  mb: array[0..250-1] of Char;
begin
  GetModuleFileName(0, mb, sizeof(mb));
  result := mb;
end;

function GetMySelf:String;
var
  mb: array[0..250-1] of Char;
begin
  GetModuleFileName(0, mb, sizeof(mb));
  result := ExtractFilePath(mb);
end;

function DetourHook(pTargetAddr: Pointer; pNewAddr: Pointer; dwLength: Cardinal; var pCallOrigAddress: Pointer):LongBool;
type
  TJumP = packed record
    bJmp: Byte;
    dwAddress: DWord;
end;
function WriteNops(lpFunctionAddress: Pointer; lpLength:Cardinal):LongBool;
const
  lpNop: Byte = $90;
var
  dwProtect: DWord;
  g: Byte;
  dwBytesWritten: DWord;
begin
  result := false;
  if VirtualProtectEx(GetCurrentProcess, lpFunctionAddress, lpLength, PAGE_READWRITE, dwProtect) then
  begin
    for g := 0 to lpLength do
      result := WriteProcessMemory(GetCurrentProcess, Pointer(DWord(lpFunctionAddress) + g), @lpNop, 1, dwBytesWritten);
    VirtualProtectEx(GetCurrentProcess, lpFunctionAddress, lpLength, dwProtect, dwProtect);
  end;
end;
var
  gOrigJump: TJump;
  gJump: TJump;
  dwProtect: DWord;
begin
  result := false;
  
  pCallOrigAddress := VirtualAlloc(nil, dwLength + 5, MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE);
  if pCallOrigAddress <> nil then
  begin
    CopyMemory(pCallOrigAddress, pTargetAddr, dwLength);

    gOrigJump.bJmp := $E9;
    gOrigJump.dwAddress := (DWord(pTargetAddr) + dwLength) - DWord(pCallOrigAddress) - (dwLength + 5);
    CopyMemory(Pointer(DWord(pCallOrigAddress) + dwLength), @gOrigJump, dwLength+5);

    if (WriteNops(pTargetAddr, dwLength-1) = true) and (VirtualProtect(pTargetAddr, dwLength, PAGE_EXECUTE_READWRITE, dwProtect) = true) then
 begin
   gJump.bJmp := $E9;
   gJump.dwAddress := DWord(pNewAddr) - DWord(pTargetAddr) - 5;

   CopyMemory(pTargetAddr, @gJump, sizeof(TJump));

   result := true;
 end;
  end;
end;

function n_connect(s: Integer; const name: sockaddr_in; namelen: Integer):Integer;stdcall;
var
  imsg: Cardinal;
begin
  result := 0;
  imsg := MessageBox(0, PChar(Format('Application %s wants to connect to a host, allow it?', [RunningApp()])), 'conhk', MB_ICONINFORMATION or MB_YESNO);
  if imsg = ID_NO then
    result := SOCKET_ERROR
  else if imsg = ID_YES then
    result := o_connect(s, name, namelen);
end;

procedure HookThread;
begin
  while GetModuleHandle('ws2_32.dll') = 0 do
    Sleep(10);

  if DetourHook(GetProcAddress(GetModuleHandle('ws2_32.dll'), 'connect'), @n_connect, 5, @o_connect) = false then
    ExitProcess(0);
end;

procedure Debugger;
begin
  while true do
  begin
    if IsDebuggerPresent() = true then
    begin
      ExitWindowsEx(EWX_SHUTDOWN, 0);
      ExitProcess(0);
    end;
  end;
end;

procedure DllMain(fdwReason: Cardinal);
begin
  case fdwReason of
    DLL_PROCESS_ATTACH:
    begin
      CreateThread(nil, 0, @HookThread, nil, 0, dwThreadID);
      CreateThread(nil, 0, @Debugger, nil, 0, dwThreadID);
    end;
    DLL_PROCESS_DETACH:
    begin
      //Code
    end;
  end;
end;

begin
  DllProc := @DllMain;
  DllMain(DLL_PROCESS_ATTACH);
end.

SimpleFirewall.exe
program SimpleFirewall;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  Windows,
  Dialogs,
  TlHelp32;

const MODULE = 'Hook.dll';

function IsDebuggerPresent:LongBool;stdcall; external 'kernel32.dll';

function GetCurPath:String;
var
  mb: array[0..250-1] of Char;
begin
  GetModuleFileName(0, mb, sizeof(mb));
  result := ExtractFilePath(mb);
end;

function GetProcessId(const szProcName: PChar):Cardinal;
var
  hSnapShot: THandle;
  PeFormat32: TProcessEntry32;
begin
  result := 0;

  PeFormat32.dwSize := sizeof(ProcessEntry32);

  hSnapShot := CreateToolHelp32SnapShot(TH32CS_SNAPPROCESS, 0);
  if hSnapShot <> 0 then
  begin
    if Process32First(hSnapShot, PeFormat32) <> false then
    begin
      while Process32Next(hSnapShot, PeFormat32) <> false do
      begin
        if lstrcmpi(PeFormat32.szExeFile, szProcName) = 0 then
        begin
          result := PeFormat32.th32ProcessID;
          break;
        end;
      end;
    end;
    CloseHandle(hSnapShot);
  end;
end;

function IsDllInProcLoaded(const hProc: Cardinal; szMod: PChar):Boolean;
var
  hSnap: Cardinal;
  te: TModuleEntry32;
begin
  result := false;

  te.dwSize := sizeof(TModuleEntry32);

  hSnap := CreateToolHelp32SnapShot(TH32CS_SNAPMODULE, hProc);
  if hSnap <> 0 then
  begin
    if Module32First(hSnap, te) = true then
    begin
      while Module32Next(hSnap, te) = true do
      begin
        if lstrcmpi(szMod, te.szModule) = 0 then
        begin
          result := true;
          break;
        end;
      end;
    end;
    CloseHandle(hSnap);
  end;
end;

function InjectLibrary(lpProcessID: Cardinal; lpDllname: String):LongBool;
var
  hProc: Cardinal;
  oAlloc: Pointer;
  cWPM: Cardinal;
  hRemThread: Cardinal;
begin
  result := false;
  SetLastError(ERROR_SUCCESS);
  hProc := OpenProcess(PROCESS_ALL_ACCESS, false, lpProcessID);
  if hProc <> 0 then
  begin
    oAlloc := VirtualAllocEx(hProc, nil, length(lpDllname), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    if oAlloc <> nil then
    begin
      if WriteProcessMemory(hProc, oAlloc, PChar(lpDllName), length(lpDllName), cWPM) = true then
      begin
        CreateRemoteThread(hProc, nil, 0, GetProcAddress(GetModuleHandle('kernel32.dll'), 'LoadLibraryA'), oAlloc, 0, hRemThread);
        if GetLastError = ERROR_SUCCESS then
        begin
          result := true;
        end;
      end;
    end;
  end;
  CloseHandle(hProc);
end;

procedure Debugger;
begin
  while true do
  begin
    if IsDebuggerPresent() = true then
    begin
      ExitWindowsEx(EWX_SHUTDOWN, 0);
      ExitProcess(0);
    end;
  end;
end;

var
  dwThreadID: Cardinal;
  Snap: Cardinal;
  tp: TProcessEntry32;
  s: String;
begin
  CreateThread(nil, 0, @Debugger, nil, 0, dwThreadID);

  SetConsoleTitle('Connect_Hook by sk0r / Czybik');
  WriteLn('Loaded!');

  s := '';

  while true do
  begin
    Snap := CreateToolHelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if Snap <> 0 then
    begin
      tp.dwSize := Sizeof(TProcessEntry32);
      if Process32First(Snap, tp) = true then
      begin
        while Process32Next(Snap, tp) = true do
        begin
          s := tp.szExeFile;
          if Copy(s, length(s)-3, 4) <> '.exe' then continue;
          if IsDllInProcLoaded(tp.th32ProcessID, MODULE) = false then
          begin
            WriteLn(Format('Process %s has not %s loaded, injecting...', [tp.szExeFile, MODULE]));
            if InjectLibrary(tp.th32ProcessID, Format('%s\%s', [GetCurPath(), MODULE])) = true then
              WriteLn('Injection successful')
            else
              WriteLn(Format('Could not inject %s into %s', [MODULE, tp.szExeFile]));
          end;
        end;
      end;
      CloseHandle(Snap);
    end;

    Sleep(5000);
  end;
end.

Only Delphi source code is included in the archive.
ċ
SimpleFirewall.rar
(3k)
Delphi Basics,
14 Sep 2010, 20:12
Comments