Magic API Hook

posted 16 Mar 2010 07:50 by Delphi Basics   [ updated 24 Feb 2011 12:55 ]
Magic Api Hook Engine v1.0 is a simple UserMode (Ring3) all around process api hooker just for WinNT family.
Magic Api Hook Engine is open source.

The archive contains usage samples.

Coder: Magic_h2001

In computer programming, the term hooking  covers a range of techniques used to alter or augment the behavior of an operating system, of applications, or of other software components by intercepting function calls or messages or events passed between software components. Code that handles such intercepted function calls, events or messages is called a "hook".

Read more: http://en.wikipedia.org/wiki/Hooking

unit MagicApiHook;
(*
==============================================
Magic Api Hook Engine v1.0 - Date: 2006.04.24
this is a simple all around process api hooker
UserMode(Ring3) just for WinNT family
By: Magic_h2001 - magic_h2001@yahoo.com
Home: http://magic.shabgard.org
==============================================
*)
interface

uses Windows;

function LowCaseStr(S:string):string;
function UpCaseStr(S:string):string;
function StrCmp(String1,String2:string):Boolean;
function Trim(S:string):string;
function StrToInt(S:string):Integer;
function StrToInt64(S:string):Int64;
function IntToStr(i:Int64):string;
function IntToHex(i:Int64; P:Int64=0):string;
function HexToInt(S:string):Integer;
function HexToInt64(S:string):Int64;
function WideToStr(const WS:WideString):string;
function StrToWide(const S:AnsiString):WideString;
function GetWin:string;
function GetSys:string;
function GetTmp:string;
function IsWinNT:Boolean;
function IsWin9x:Boolean;
function IsAdmin:Boolean;
function GetPath(Path:string):string;
function GetFile(Path:string):string;
function GetFileInfo(Filename,BlockKey:string):string;
function IsFileExist(FileName:string):Boolean;
function IsFileInUse(FileName:string):Boolean;
function DebugPrivilege(ToEnable:Boolean):Boolean;
function GetExplorerPid:DWORD;
function PHandleToPID(dwProcessHandle:DWord):DWord;
function CalcJump(Src,Dest:DWORD):DWORD;
function InjectDll(DllPath:string; PID_or_PHD:DWORD):Boolean;
function UnInjectDll(DllName:string; PID_or_PHD:DWORD):Boolean;
function ApiHook(ModName,ApiName:Pchar; FuncAddr,HookedApi:Pointer; var MainApi:Pointer):Boolean;
function ApiUnHook(ModName,ApiName:Pchar; FuncAddr,HookedApi:Pointer; var MainApi:Pointer):Boolean;
function InjectAllProc(DllPath:string):Integer;
function UnInjectAllProc(DllPath:string):Integer;
function IsHeuristicScan:Boolean;
function OpCodeLength(Address:DWORD):DWORD; cdecl;

implementation

const
  TH32CS_SNAPPROCESS=$00000002;

type
  tagPROCESSENTRY32=packed record
    dwSize: DWORD;
    cntUsage: DWORD;
    th32ProcessID: DWORD;
    th32DefaultHeapID: DWORD;
    th32ModuleID: DWORD;
    cntThreads: DWORD;
    th32ParentProcessID: DWORD;
    pcPriClassBase: Longint;
    dwFlags: DWORD;
    szExeFile: array[0..MAX_PATH-1] of Char;
  end;
  PROCESSENTRY32=tagPROCESSENTRY32;
  TProcessEntry32=tagPROCESSENTRY32;

var LoadOpCodes: array[0..23] of Byte=($68,0,0,0,0,$E8,0,0,0,0,$B8,$FF,$FF,$FF,$FF,$50,$E8,0,0,0,0,$EB,$F3,$C3);
    FreeOpCodes: array[0..32] of Byte=($68,0,0,0,0,$E8,0,0,0,0,$B9,$FF,$FF,0,0,$50,$51,$50,$E8,0,0,0,0,$59,$83,$F8,$00,$58,$74,$02,$E2,$EF,$C3);

 CreateToolhelp32Snapshot: function(dwFlags, th32ProcessID: DWORD): THandle; stdcall;
 Process32First: function(hSnapshot: THandle; var lppe: TProcessEntry32): BOOL; stdcall;
 Process32Next: function(hSnapshot: THandle; var lppe: TProcessEntry32): BOOL; stdcall;
 OpenProcess: function(dwDesiredAccess:DWORD; bInheritHandle:BOOL; dwProcessId:DWORD):THandle; stdcall;
 VirtualAllocEx: function(hProcess:THandle; lpAddress:Pointer; dwSize,flAllocationType:DWORD; flProtect:DWORD):Pointer; stdcall;
 WriteProcessMemory: function(hProcess:THandle; const lpBaseAddress:Pointer; lpBuffer:Pointer; nSize:DWORD; var lpNumberOfBytesWritten:DWORD):BOOL; stdcall;
 CreateRemoteThread: function(hProcess:THandle; lpThreadAttributes:Pointer; dwStackSize:DWORD; lpStartAddress:TFNThreadStartRoutine; lpParameter:Pointer; dwCreationFlags:DWORD; var lpThreadId:DWORD):THandle; stdcall;

(******************************************************************************)
function LowCaseStr(S:string):string;
var i: Integer;
begin
 Result:=S;
 if S='' then Exit;
 for i:=1 to Length(S) do if Result[i] in ['A'..'Z'] then Inc(Result[i],32);
end;
(******************************************************************************)
function UpCaseStr(S:string):string;
var i: Integer;
begin
 Result:=S;
 if S='' then Exit;
 for i:=1 to Length(S) do Result[i]:=UpCase(Result[i]);
end;
(******************************************************************************)
function StrCmp(String1,String2:string):Boolean;
begin
 Result:=lstrcmpi(Pchar(String1),Pchar(String2))=0;
end;
(******************************************************************************)
function Trim(S:string):string;
begin
 Result:='';
 if S='' then Exit;
 while S[1]=' ' do begin
  Delete(S,1,1);
  if S='' then Exit;
 end;
 while S[Length(S)]=' ' do begin
  Delete(S,Length(S),1);
  if S='' then Exit;
 end;
 Result:=S;
end;
(******************************************************************************)
function IntToStr(i:Int64):string;
begin
 try
  Str(i,Result);
 except
  Result:='';
 end;
end;
(******************************************************************************)
function StrToInt(S:string):Integer;
var Code: Integer;
begin
 Val(S, Result, Code);
 if Code<>0 then Result:=0;
end;
(******************************************************************************)
function StrToInt64(S:string):Int64;
var Code: Integer;
begin
 Val(S, Result, Code);
 if Code<>0 then Result:=0;
end;
(******************************************************************************)
function HexToInt(S:string):Integer;
var Tmp: string;
begin
 Result:=0;
 Tmp:='';
 if S='' then Exit;
 if (S[1]='-') or (S[1]='+') then begin
   Tmp:=S[1];
   Delete(S,1,1);
  end;
 S:=Tmp+'$'+S;
 Result:=StrToInt(S);
end;
(******************************************************************************)
function HexToInt64(S:string):Int64;
var Tmp: string;
begin
 Result:=0;
 Tmp:='';
 if S='' then Exit;
 if (S[1]='-') or (S[1]='+') then begin
   Tmp:=S[1];
   Delete(S,1,1);
  end;
 S:=Tmp+'$'+S;
 Result:=StrToInt64(S);
end;
(******************************************************************************)
function IntToHex(i:Int64; P:Int64=0):string;
const
  Hexa:array[0..$F] of char='0123456789ABCDEF';
begin
 Result:='';
 if (P=0) and (i=0) then begin
  Result:='0';
  Exit;
 end;
 while (P>0)or(i>0) do begin
  Dec(P,1);
  Result:=Hexa[i and $F]+Result;
  i:=i shr 4;
 end;
end;
(******************************************************************************)
function WideToStr(const WS:WideString):string;
var l: Integer;
begin
 Result:='';
 if WS='' then Exit;
 l:=WideCharToMultiByte(CP_ACP,0,@WS[1],-1,nil,0,nil,nil);
 SetLength(Result,l-1);
 if l>1 then WideCharToMultiByte(CP_ACP,0,@WS[1],-1,@Result[1],l-1,nil,nil);
end;
(******************************************************************************)
function StrToWide(const S:AnsiString):WideString;
var l: Integer;
begin
 Result:='';
 if S='' then Exit;
 l:=MultiByteToWideChar(CP_ACP,0, Pchar(@S[1]),-1,nil,0);
 SetLength(Result,l-1);
 if l>1 then MultiByteToWideChar(CP_ACP,0,Pchar(@S[1]),-1,PWideChar(@Result[1]),l-1);
end;
(******************************************************************************)
function GetWin:string;
var
  Gwin : array[0..MAX_PATH] of Char;
begin
  GetWindowsDirectory(Gwin,MAX_PATH);
  Result:=Gwin;
  if Length(Result)>0 then
  if Result[Length(Result)]<>'\' then Result:=Result+'\';
end;
(******************************************************************************)
function GetSys:string;
var
  Gsys : array[0..MAX_PATH] of Char;
begin
  GetSystemDirectory(Gsys,MAX_PATH);
  Result:=Gsys;
  if Length(Result)>0 then
  if Result[Length(Result)]<>'\' then Result:=Result+'\';
end;
(******************************************************************************)
function GetTmp:string;
var
  Gtmp : array[0..MAX_PATH] of Char;
begin
  GetTempPath(MAX_PATH,Gtmp);
  Result:=Gtmp;
  if Length(Result)>0 then
  if Result[Length(Result)]<>'\' then Result:=Result+'\';
end;
(******************************************************************************)
function IsWinNT:Boolean;
var osVerInfo: TOSVersionInfo;
begin
 Result:=False;
 osVerInfo.dwOSVersionInfoSize:=SizeOf(TOSVersionInfo);
 if GetVersionEx(osVerInfo) then Result:=(osVerInfo.dwPlatformId=VER_PLATFORM_WIN32_NT);
end;
(******************************************************************************)
function IsWin9x:Boolean;
asm
 MOV     EAX, FS:[030H]
 TEST    EAX, EAX
 SETS    AL
end;
(******************************************************************************)
function IsAdmin:Boolean;
const
  SECURITY_NT_AUTHORITY: TSIDIdentifierAuthority = (Value: (0,0,0,0,0,5));
  SECURITY_BUILTIN_DOMAIN_RID = $00000020;
  DOMAIN_ALIAS_RID_ADMINS     = $00000220;
var
  IsUserAnAdmin: function(): BOOL; stdcall;
  hAccessToken: THandle;
  ptgGroups: PTokenGroups;
  dwInfoBufferSize: DWORD;
  psidAdministrators: PSID;
  xi: Integer;
  bSuccess: BOOL;
  hMod: Thandle;
begin
 Result:=True; 
 if IsWin9x then Exit;
 Result:=False;
 hAccessToken:=0;
 hMod:=GetModuleHandle('shell32.dll');
 if hMod=0 then hMod:=LoadLibrary('shell32.dll');
 IsUserAnAdmin:=GetProcAddress(hMod,'IsUserAnAdmin');
 if not Assigned(IsUserAnAdmin) then begin
  bSuccess:=OpenThreadToken(GetCurrentThread,TOKEN_QUERY,True,hAccessToken);
  if not bSuccess then if GetLastError=ERROR_NO_TOKEN then
   bSuccess:=OpenProcessToken(GetCurrentProcess,TOKEN_QUERY,hAccessToken);
  if bSuccess then begin
    GetMem(ptgGroups,1024);
    bSuccess:=GetTokenInformation(hAccessToken,TokenGroups,ptgGroups,1024,dwInfoBufferSize);
    CloseHandle(hAccessToken);
    if bSuccess then begin
      AllocateAndInitializeSid(SECURITY_NT_AUTHORITY,2,SECURITY_BUILTIN_DOMAIN_RID,DOMAIN_ALIAS_RID_ADMINS,0,0,0,0,0,0,psidAdministrators);
      if ptgGroups.GroupCount>0 then
        for xi:=0 to ptgGroups.GroupCount-1 do
         if EqualSid(psidAdministrators,ptgGroups.Groups[xi].Sid) then begin
          Result:=True;
          Break;
         end;
      FreeSid(psidAdministrators);
    end;
    FreeMem(ptgGroups);
  end;
 end
 else Result:=IsUserAnAdmin();
end;
(******************************************************************************)
function GetPath(Path:string):string;
begin
 Result:='';
 if Path='' then Exit;
 if Pos('\',Path)<>0 then begin
   while Path[Length(Path)]<>'\' do Delete(Path,Length(Path),1);
   Result:=Path;
   Exit;
 end;
 if Pos('/',Path)<>0 then begin
   while Path[Length(Path)]<>'/' do Delete(Path,Length(Path),1);
   Result:=Path;
   Exit;
 end;
end;
(******************************************************************************)
function GetFile(Path:string):string;
begin
 while Pos(':',Path)<>0 do Delete(Path,1,Pos(':',Path));
 while Pos('\',Path)<>0 do Delete(Path,1,Pos('\',Path));
 while Pos('/',Path)<>0 do Delete(Path,1,Pos('/',Path));
 Result:=Path;
end;
(******************************************************************************)
function GetFileInfo(Filename,BlockKey:string):string;
var Size,VSize,Dummy: Longword;
    Pbuff,Plang: Pointer;
    Pvalue: Pchar;
    Qroot: string;
begin
 Result:='';
 Size:=GetFileVersionInfoSize(Pchar(Filename),Dummy);
 if Size=0 then Exit;
 GetMem(Pbuff,Size);
 try
 if GetFileVersionInfo(Pchar(Filename),0,Size,Pbuff) then begin
   Qroot:='\StringFileInfo\040904E4\';
   if not VerQueryValue(Pbuff,Pchar(Qroot+BlockKey),Pointer(Pvalue),VSize) then begin
     if VerQueryValue(Pbuff,Pchar('\VarFileInfo\Translation'),Plang,VSize) then begin
       Qroot:=IntToHex(Integer(Plang^),8);
       Qroot:=Copy(Qroot,5,4)+Copy(Qroot,1,4);
       Qroot:='\StringFileInfo\'+Qroot+'\';
       if not VerQueryValue(Pbuff,Pchar(Qroot+BlockKey),Pointer(Pvalue),VSize) then Exit;
     end else Exit;
   end;
   Result:=Pvalue;
 end;
 finally
   FreeMem(Pbuff);
 end;
end;
(******************************************************************************)
function IsFileExist(FileName:string):Boolean;
var
 cHandle:THandle;
 FindData:TWin32FindData;
begin
 cHandle:=FindFirstFileA(Pchar(FileName),FindData);
 Result:=cHandle<>INVALID_HANDLE_VALUE;
 if Result then FindClose(cHandle);
end;
(******************************************************************************)
function IsFileInUse(FileName:string):Boolean;
var HFileRes: HFile;
begin
 Result:=False;
 if IsFileExist(FileName) then begin
  HFileRes := CreateFile(Pchar(FileName),GENERIC_READ or GENERIC_WRITE,
              FILE_SHARE_READ or FILE_SHARE_WRITE,nil,OPEN_EXISTING,0,0);
  Result:=(HFileRes=INVALID_HANDLE_VALUE);
  if Result=False then CloseHandle(HFileRes);
 end;
end;
(******************************************************************************)
function DebugPrivilege(ToEnable:Boolean):Boolean;
var
 OldTokenPrivileges, TokenPrivileges: TTokenPrivileges;
 ReturnLength: DWORD;
 hToken: THandle;
 Luid: Int64;
begin
 Result:=True;
 if IsWin9x then Exit;
 Result:=False;
 if not OpenProcessToken(GetCurrentProcess,TOKEN_ADJUST_PRIVILEGES,hToken) then Exit;
 try
  if not LookupPrivilegeValue(nil,'SeDebugPrivilege',Luid) then Exit;
  TokenPrivileges.Privileges[0].luid:=Luid;
  TokenPrivileges.PrivilegeCount:=1;
  TokenPrivileges.Privileges[0].Attributes:=0;
  AdjustTokenPrivileges(hToken,False,TokenPrivileges,SizeOf(TTokenPrivileges),OldTokenPrivileges,ReturnLength);
  OldTokenPrivileges.Privileges[0].luid:=Luid;
  OldTokenPrivileges.PrivilegeCount:=1;
  if ToEnable then OldTokenPrivileges.Privileges[0].Attributes:=TokenPrivileges.Privileges[0].Attributes or SE_PRIVILEGE_ENABLED
  else OldTokenPrivileges.Privileges[0].Attributes:=TokenPrivileges.Privileges[0].Attributes and (not SE_PRIVILEGE_ENABLED);
  Result:=AdjustTokenPrivileges(hToken,False,OldTokenPrivileges,ReturnLength,PTokenPrivileges(nil)^,ReturnLength);
 finally
  CloseHandle(hToken);
 end;
end;
(******************************************************************************)
function GetExplorerPid:DWORD;
begin
 GetWindowThreadProcessID(FindWindow('Shell_TrayWnd',nil), @Result );
end;
(******************************************************************************)
function PHandleToPID(dwProcessHandle:DWord):DWord;
type
 TPI=packed record
       Reserved1      : Pointer;
       PebBaseAddress : Pointer;
       Reserved2      : array[0..1] of Pointer;
       UniqueProcessId: DWord;
       Reserved3      : Pointer;
     end;
 PPI=^TPI;
var
 NtQueryInformationProcess: function(dwHandle: DWord; dwInfo: DWord; pbi: PPI; dwSize: DWord; pData: Pointer): DWord; stdcall;
 pbi: TPI;
 dwDupCP: DWord;
begin
 Result:=0;
 if IsWin9x then Exit;
 @NtQueryInformationProcess:=GetProcAddress(GetModuleHandle('ntdll.dll'),'NtQueryInformationProcess');
 if (@NtQueryInformationProcess<>nil) then
   if DuplicateHandle(GetCurrentProcess, dwProcessHandle, GetCurrentProcess, @dwDupCP, PROCESS_ALL_ACCESS, False, 0) then begin
     if NtQueryInformationProcess(dwDupCP,0,@pbi,SizeOf(pbi),nil)=0 then
       Result:=pbi.UniqueProcessId;
     CloseHandle(dwDupCP);
   end;
end;
(******************************************************************************)
function CalcJump(Src,Dest:DWORD):DWORD;
begin
 if(Dest<Src) then begin
   Result:=Src-Dest;
   Result:=$FFFFFFFF-Result;
   Result:=Result-4;
  end
  else begin
   Result:=Dest-Src;
   Result:=Result-5;
  end;
end;
(******************************************************************************)
function InjectDll(DllPath:string; PID_or_PHD:DWORD):Boolean;
var
 Bytes,Process,Thread,ThreadId: DWORD;
 Params: Pointer;
 LodLib,Slp,St: DWORD;
begin
 Result:=False;
 if (IsWin9x) or (DllPath='') then Exit;
 LodLib:=DWORD(GetProcAddress(GetModuleHandle('kernel32'),'LoadLibraryA'));
 Slp:=DWORD(GetProcAddress(GetModuleHandle('kernel32'),'Sleep'));
 if (@Slp=nil) or (@LodLib=nil) then Exit;
 Process:=OpenProcess(PROCESS_ALL_ACCESS,False,PID_or_PHD);
 if Process=0 then Process:=PID_or_PHD;
 Params:=VirtualAllocEx(Process,nil,$1000,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
 if Params=nil then Exit;
 WriteProcessMemory(Process,Params,Pchar(DLLPath),Length(DllPath),Bytes);
 St:=Integer(Params)+Length(DllPath)+1;
 DWORD(Pointer(DWORD(@LoadOpCodes)+1)^):=DWORD(Params);
 DWORD(Pointer(DWORD(@LoadOpCodes)+6)^):=CalcJump(St+5,LodLib);
 DWORD(Pointer(DWORD(@LoadOpCodes)+17)^):=CalcJump(St+16,Slp);
 WriteProcessMemory(Process,Pointer(St),@LoadOpCodes,SizeOf(LoadOpCodes),Bytes);
 Thread:=CreateRemoteThread(Process,nil,0,Pointer(St),nil,0,ThreadId);
 if Thread<>0 then CloseHandle(Thread);
 CloseHandle(Process);
 Result:=True;
end;
(******************************************************************************)
function UnInjectDll(DllName:string; PID_or_PHD:DWORD):Boolean;
var
 Bytes,Process,Thread,ThreadId: DWORD;
 Params: Pointer;
 FreeLib,GetMod,St: DWORD;
begin
 Result:=False;
 if (IsWin9x) or (DllName='') then Exit;
 FreeLib:=DWORD(GetProcAddress(GetModuleHandle('kernel32'),'FreeLibrary'));
 GetMod:=DWORD(GetProcAddress(GetModuleHandle('kernel32'),'GetModuleHandleA'));
 if (@FreeLib=nil) or (@GetMod=nil) then Exit;
 Process:=OpenProcess(PROCESS_ALL_ACCESS,False,PID_or_PHD);
 if Process=0 then Process:=PID_or_PHD;
 Params:=VirtualAllocEx(Process,nil,$1000,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
 if Params=nil then Exit;
 WriteProcessMemory(Process,Params,Pchar(DLLName),Length(DllName),Bytes);
 St:=Integer(Params)+Length(DllName)+1;
 DWORD(Pointer(DWORD(@FreeOpCodes)+1)^):=DWORD(Params);
 DWORD(Pointer(DWORD(@FreeOpCodes)+6)^):=CalcJump(St+5,GetMod);
 DWORD(Pointer(DWORD(@FreeOpCodes)+19)^):=CalcJump(St+18,FreeLib);
 WriteProcessMemory(Process,Pointer(St),@FreeOpCodes,SizeOf(FreeOpCodes),Bytes);
 Thread:=CreateRemoteThread(Process,nil,0,Pointer(St),nil,0,ThreadId);
 if Thread<>0 then CloseHandle(Thread);
 CloseHandle(Process);
 Result:=True;
end;
(******************************************************************************)
function ApiHook(ModName,ApiName:Pchar; FuncAddr,HookedApi:Pointer; var MainApi:Pointer):Boolean;
var
 dwCount,Cnt,i,Jmp: DWORD;
 P: Pointer;
 hMod,OldP,TMP: Cardinal;
begin
 Result:=False;
 if IsWin9x then Exit;
 P:=FuncAddr;
 if P=nil then begin
  hMod:=GetModuleHandle(ModName);
  if hMod=0 then hMod:=LoadLibrary(ModName);
  P:=GetProcAddress(hMod,ApiName);
 end;
 if (P=nil) or (HookedApi=nil) then Exit;
 if not VirtualProtect(P,$40,PAGE_EXECUTE_READWRITE,@OldP) then Exit;
 if ((Byte(P^)=$68) and (DWORD(Pointer(DWORD(P)+1)^)=DWORD(HookedApi))) then Exit;
 MainApi:=VirtualAlloc(nil,$1000,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
 if MainApi=nil then Exit;
 Cnt:=0;
 for dwCount:=0 to $3F do begin
  Inc(Cnt,OpCodeLength(DWORD(P)+Cnt));
  for i:=0 to Cnt-1 do Pchar(MainApi)[i]:=Pchar(P)[i];
  if Cnt>5 then Break;
 end;
 Pchar(MainApi)[Cnt]:=Char($68);
 DWORD(Pointer(DWORD(MainApi)+Cnt+1)^):=DWORD(P)+Cnt;
 Pchar(MainApi)[Cnt+5]:=Char($C3);
 Pchar(MainApi)[Cnt+6]:=Char($99);
 if (OpCodeLength(DWORD(MainApi))=5) and ((Byte(MainApi^)=$E8) or (Byte(MAinApi^)=$E9)) then begin
  Jmp:=DWORD(P)+DWORD(Pointer(DWORD(MainApi)+1)^)+5;
  DWORD(Pointer(DWORD(MainApi)+1)^):=CalcJump(DWORD(MainApi),Jmp);
 end;
 Pchar(P)[0]:=Char($68);
 DWORD(Pointer(DWORD(P)+1)^):=DWORD(HookedApi);
 Pchar(P)[5]:=Char($C3);
 VirtualProtect(P,$40,OldP,@TMP);
 Result:=True;
end;
(******************************************************************************)
function ApiUnHook(ModName,ApiName:Pchar; FuncAddr,HookedApi:Pointer; var MainApi:Pointer):Boolean;
var
 dwCount,Cnt,i,Jmp: DWORD;
 P: Pointer;
 hMod,OldP,TMP: Cardinal;
begin
 Result:=False;
 if IsWin9x then Exit;
 P:=FuncAddr;
 if P=nil then begin
  hMod:=GetModuleHandle(Pchar(ModName));
  P:=GetProcAddress(hMod,Pchar(ApiName));
 end;
 if (P=nil) or (MainApi=nil) or (HookedApi=nil) then Exit;
 if not VirtualProtect(P,$40,PAGE_EXECUTE_READWRITE,@OldP) then Exit;
 if ((Byte(P^)<>$68) or (DWORD(Pointer(DWORD(P)+1)^)<>DWORD(HookedApi))) then Exit;
 Cnt:=0;
 for dwCount:=0 to $3F do begin
  Inc(Cnt,OpCodeLength(DWORD(MainApi)+Cnt));
  if (Byte(Pointer(DWORD(MainApi)+Cnt)^)=$C3) and (Byte(Pointer(DWORD(MainApi)+Cnt+1)^)=$99) then Break;
  for i:=0 to Cnt-1 do Pchar(P)[i]:=Pchar(MainApi)[i];
 end;
 if (OpCodeLength(DWORD(P))=5) and ((Byte(P^)=$E8) or (Byte(P^)=$E9)) then begin
  Jmp:=DWORD(MainApi)+DWORD(Pointer(DWORD(MainApi)+1)^)+5;
  DWORD(Pointer(DWORD(P)+1)^):=CalcJump(DWORD(P),Jmp);
 end;
 VirtualProtect(P,$40,OldP,@TMP);
 VirtualFree(MainApi,0,MEM_RELEASE);
 Result:=True;
end;
(******************************************************************************)
function InjectAllProc(DllPath:string):Integer;
var
 hSnapP: THandle;
 ProcInfo: ProcessEntry32;
begin
 Result:=0;
 hSnapP:=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
 if hSnapP=INVALID_HANDLE_VALUE then Exit;
 ProcInfo.dwSize:=SizeOf(ProcessEntry32);
 if Process32First(hSnapP,ProcInfo) then
 repeat
  if InjectDll(DllPath,ProcInfo.th32ProcessID) then Inc(Result);
 until not Process32Next(hSnapP,ProcInfo);
 CloseHandle(hSnapP);
end;
(******************************************************************************)
function UnInjectAllProc(DllPath:string):Integer;
var
 hSnapP: THandle;
 ProcInfo: ProcessEntry32;
begin
 Result:=0;
 hSnapP:=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
 if hSnapP=INVALID_HANDLE_VALUE then Exit;
 ProcInfo.dwSize:=SizeOf(ProcessEntry32);
 if Process32First(hSnapP,ProcInfo) then
 repeat
  if UnInjectDll(DllPath,ProcInfo.th32ProcessID) then Inc(Result);
 until not Process32Next(hSnapP,ProcInfo);
 CloseHandle(hSnapP);
end;
(******************************************************************************)
function RDTSC: Int64; assembler;
asm
  DB 0fh ,031h
end;
(******************************************************************************)
function IsHeuristicScan:Boolean;
var
 Tm1,Tm2: Int64;
 Tc1,Tc2: DWORD;
begin
 // Method by: Magic_h2001
 Tm1:=RDTSC;
 Tc1:=GetTickCount;
 Sleep(100);
 Tm2:=RDTSC-Tm1;
 Tc2:=GetTickCount-Tc1;
 Result:=(Tm2<50000000) or (Tc2<50);
end;
(******************************************************************************)
function OpCodeLength(Address:DWORD):DWORD; cdecl; assembler;
const
  O_UNIQUE = 0;
  O_PREFIX = 1;
  O_IMM8 = 2;
  O_IMM16 = 3;
  O_IMM24 = 4;
  O_IMM32 = 5;
  O_IMM48 = 6;
  O_MODRM = 7;
  O_MODRM8 = 8;
  O_MODRM32 = 9;
  O_EXTENDED = 10;
  O_WEIRD = 11;
  O_ERROR = 12;
asm
pushad
cld
xor edx, edx
mov esi, Address
  mov ebp, esp
push 1097F71Ch
push 0F71C6780h
push 17389718h
push 101CB718h
push 17302C17h
push 18173017h
push 0F715F547h
push 4C103748h
push 272CE7F7h
push 0F7AC6087h
push 1C121C52h
push 7C10871Ch
push 201C701Ch
push 4767602Bh
push 20211011h
push 40121625h
push 82872022h
push 47201220h
push 13101419h
push 18271013h
push 28858260h
push 15124045h
push 5016A0C7h
push 28191812h
push 0F2401812h
push 19154127h
push 50F0F011h
mov ecx, 15124710h
push ecx
push 11151247h
push 10111512h
push 47101115h
mov eax, 12472015h
push eax
push eax
push 12471A10h
add cl, 10h
push ecx
sub cl, 20h
push ecx
xor ecx, ecx
dec ecx
@@ps:
inc  ecx
mov  edi, esp
@@go:
lodsb
mov  bh, al
@@ft:
mov  ah, [edi]
inc  edi
shr  ah, 4
sub  al, ah
jnc  @@ft
mov al, [edi-1]
and al, 0Fh
cmp  al, O_ERROR
jnz  @@i7
pop edx
not edx
@@i7:
inc edx
cmp al, O_UNIQUE
jz @@t_exit
cmp al, O_PREFIX
jz @@ps
add  edi, 51h
cmp  al, O_EXTENDED
jz   @@go
mov edi, [ebp+((1+8)*4)+4]
@@i6:
    inc  edx
    cmp  al, O_IMM8
    jz   @@t_exit
    cmp  al, O_MODRM
    jz   @@t_modrm
    cmp  al, O_WEIRD
    jz   @@t_weird
@@i5:
    inc  edx
    cmp  al, O_IMM16
    jz   @@t_exit
    cmp  al, O_MODRM8
    jz   @@t_modrm
@@i4:
    inc  edx
    cmp  al, O_IMM24
    jz   @@t_exit
@@i3:
    inc  edx
@@i2:
    inc  edx
    pushad
    mov  al, 66h
    repnz scasb
    popad
    jnz  @@c32
@@d2:
    dec  edx
    dec  edx
@@c32:
    cmp  al, O_MODRM32
    jz   @@t_modrm
    sub  al, O_IMM32
    jz   @@t_imm32
@@i1:
    inc  edx
@@t_exit:
    jmp @@ASMEnded
@@t_modrm:
       lodsb
       mov  ah, al
       shr  al, 7
       jb   @@prmk
       jz   @@prm
       add  dl, 4
       pushad
       mov  al, 67h
       repnz scasb
       popad
       jnz  @@prm
@@d3:  sub  dl, 3
       dec  al
@@prmk:jnz  @@t_exit
       inc  edx
       inc  eax
@@prm:
       and  ah, 00000111b
       pushad
       mov  al, 67h
       repnz scasb
       popad
       jz   @@prm67chk
       cmp  ah, 04h
       jz   @@prmsib
       cmp  ah, 05h
       jnz  @@t_exit
@@prm5chk:
       dec  al
       jz   @@t_exit
@@i42: add  dl, 4
       jmp  @@t_exit
@@prm67chk:
       cmp  ax, 0600h
       jnz  @@t_exit
       inc  edx
       jmp  @@i1
@@prmsib:
       cmp  al, 00h
       jnz  @@i1
       lodsb
       and  al, 00000111b
       sub  al, 05h
       jnz  @@i1
       inc  edx
       jmp  @@i42
@@t_weird:
       test byte ptr [esi], 00111000b
       jnz  @@t_modrm
       mov  al, O_MODRM8
       shr  bh, 1
       adc  al, 0
       jmp  @@i5
@@t_imm32:
       sub  bh, 0A0h
       cmp  bh, 04h
       jae  @@d2
       pushad
       mov  al, 67h
       repnz scasb
       popad
       jnz  @@chk66t
@@d4:  dec  edx
       dec  edx
@@chk66t:
       pushad
       mov  al, 66h
       repnz scasb
       popad
       jz   @@i1
       jnz  @@d2
@@ASMEnded:
    mov esp, ebp
    mov [result+(9*4)], edx
    popad
end;
(******************************************************************************)
initialization
 if IsHeuristicScan then Halt; // undetecting from Avs...
 @OpenProcess:=GetProcAddress(GetModuleHandle('kernel32'),'OpenProcess');
 @VirtualAllocEx:=GetProcAddress(GetModuleHandle('kernel32'),'VirtualAllocEx');
 @WriteProcessMemory:=GetProcAddress(GetModuleHandle('kernel32'),'WriteProcessMemory');
 @CreateRemoteThread:=GetProcAddress(GetModuleHandle('kernel32'),'CreateRemoteThread');
 @CreateToolhelp32Snapshot:=GetProcAddress(GetModuleHandle('kernel32'),'CreateToolhelp32Snapshot');
 @Process32First:=GetProcAddress(GetModuleHandle('kernel32'),'Process32First');
 @Process32Next:=GetProcAddress(GetModuleHandle('kernel32'),'Process32Next');

end.

Č
ċ
MagicApiHook.7z
(9k)
Delphi Basics,
16 Mar 2010 07:53
Comments