Simple Firewall

Post date: Sep 15, 2010 3:10:28 AM

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.