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.