madCHook.pas

//  madCHook.pas          version:  2.0   ?  date: 2003-08-10
//  ----------
//  API hooking, code hooking
//  ----------
//  Copyright (C) 1999 - 2003 www.madshi.net, All Rights Reserved
// **********

// 2003-08-10 2.0  (1) HookCode parameters changed -> only one flags parameter
//          (2) (Un)InjectLibrary: user/session/system wide injection!
//          (3) InjectLibrary2 replaced by InjectLibrary (auto detect)
//          (4) static lib for Microsoft C++ added
//          (5) CreateIpcQueue + SendIpcMessage + DestroyIpcQueue added
//          (6) AmSystemProcess + AmUsingInputDesktop added
//          (7) GetCurrentSessionId + GetInputSessionId added
//          (8) GetCallingModule function added
//          (9) ProcessIdToFileName added
//          (a) Create/OpenGlobalMutex + Event + FileMapping added
//          (b) WideToAnsi + AnsiToWide functions added
//          (c) RenewHook function added
//          (d) madCodeHook.dll -> madCHook.dll (8.3 dos name logic)
//          (e) UnhookAPI added (= UnhookCode, added just for the look)
//          (f) AddAccessForEveryone added
// 2002-10-17 1.3f InjectLibrary2(W) was not stdcall (dumb me)
// 2002-10-03 1.3e (1) InjectLibraryW added
//          (2) InjectLibrary2(W) added for use in CreateProcess(W) hooks
// 2002-09-22 1.3d CreateProcessExW added
// 2002-03-24 1.3c CollectHooks/FlushHooks speed up mixture initialization
// 2002-02-24 1.3b LPSTARTUPINFO -> LPSTARTUPINFOA
// 2002-01-21 1.3a ProcessHandleToId exported
// 2001-07-08 1.3  new functions (1) AllocMemEx & FreeMemEx
//          (2) CopyFunction
//          (3) CreateRemoteThread and
//          (4) InjectLibrary added
// 2001-04-20 1.2a you can now force HookCode/API to use the mixture mode
// 2001-04-16 1.2  new function CreateProcessEx -> dll injecting

unit madCHook;

interface

uses Windows;

// **********

type TPCardinal = ^cardinal;
     TPPointer  = ^pointer;

// **********

const
  // by default madCodeHook counts how many times any thread is currently
  // running inside of your callback function
  // this way unhooking can be safely synchronized to that counter
  // sometimes you don't need/want this counting to happen, e.g.
  // (1) if you don't plan to ever unhook, anyway
  // (2) if the counting performance drop is too high for your taste
  // (3) if you want to unhook from inside the hook callback function
  // in those cases you can set the flag "DONT_COUNT"
  DONT_COUNT = $00000001;

  // madCodeHook implements two different API hooking methods
  // the mixture mode is the second best method, it's only used if the main
  // hooking method doesn't work for whatever reason (e.g. API code structure)
  // normally madCodeHook chooses automatically which mode to use
  // you can force madCodeHook to use the mixture mode by specifying this flag:
  MIXTURE_MODE = $00000002;

  // under win9x you can hook code system wide, if it begins > $80000000
  // or if the code section of the to-be-hooked dll is shared
  // the callback function is in this case automatically copied to shared memory
  // use only kernel32 APIs in such a system wide hook callback function (!!)
  // if you want an easier way and/or a NT family compatible way to hook code
  // system wide, please use InjectLibrary(ALL_SESSIONS) instead of these flags:
  SYSTEM_WIDE_9X          = $00000004;
  ACCEPT_UNKNOWN_TARGETS_9X = $00000008;

// hook any code or a specific API
function HookCode (code         : pointer;
          callbackFunc : pointer;
          out nextHook : pointer;
          flags        : dword = 0) : longBool; stdcall;
         external 'madCHook.dll';
function HookAPI (module, api  : pchar;
          callbackFunc : pointer;
          out nextHook : pointer;
          flags        : dword = 0) : longBool; stdcall;
         external 'madCHook.dll';

// some firewall/antivirus programs kill our hooks, so we need to renew them
function RenewHook (var nextHook: pointer) : longBool; stdcall;
         external 'madCHook.dll';

// unhook again
function UnhookCode (var nextHook: pointer) : longBool; stdcall;
         external 'madCHook.dll';
function UnhookAPI (var nextHook: pointer) : longBool; stdcall;
         external 'madCHook.dll';

// putting all your "HookCode/API" calls into a "CollectHooks".."FlushHooks"
// frame can eventually speed up the installation of the hooks
procedure CollectHooks; external 'madCHook.dll';
procedure   FlushHooks; external 'madCHook.dll';

// **********
// same as CreateProcess
// additionally the dll "loadLibrary" is injected into the newly created process
// the dll is loaded right before the entry point of the exe module is called

function CreateProcessEx  (applicationName, commandLine : pchar;
          processAttr, threadAttr      : PSecurityAttributes;
          inheritHandles          : longBool;
          creationFlags          : dword;
          environment          : pointer;
          currentDirectory          : pchar;
          const startupInfo          : TStartupInfo;
          var processInfo          : TProcessInformation;
          loadLibrary          : pchar          ) : longBool; stdcall;
         external 'madCHook.dll' name 'CreateProcessExA';
function CreateProcessExW (applicationName, commandLine : pwidechar;
          processAttr, threadAttr      : PSecurityAttributes;
          inheritHandles          : longBool;
          creationFlags          : dword;
          environment          : pointer;
          currentDirectory          : pchar;
          const startupInfo          : TStartupInfo;
          var processInfo          : TProcessInformation;
          loadLibrary          : pwidechar          ) : longBool; stdcall;
         external 'madCHook.dll';

// **********
// memory allocation in the specified processes (shared memory in win9x)
// if the processHandle is 0, the memory is allocated or freed in the shared
// area (in win9x) or in our own process (in winNT)

function AllocMemEx (size : dword;   processHandle : dword = 0) : pointer; stdcall; external 'madCHook.dll';
function  FreeMemEx (mem  : pointer; processHandle : dword = 0) : bool;    stdcall; external 'madCHook.dll';

// **********
// copy (and relocate) any function to a new location in any process
// if the processHandle is 0, the function is copied to shared area (in win9x)
// or to another memory location in our own process (in winNT)
// don't forget to free the function with FreeMemEx, if you don't it anymore

function CopyFunction (func          : pointer;
          processHandle        : dword     = 0;
          acceptUnknownTargets : boolean   = false;
          buffer          : TPPointer = nil  ) : pointer; stdcall;
         external 'madCHook.dll';

// **********
// like CreateRemoteThread, but 3 changes:
// (1) this one also works perfectly in win9x!!
// (2) this one also works on other sessions in winNt
// (3) the DACL of the current thread is copied in winNt (if threadAttr = nil)

function CreateRemoteThreadEx (processHandle : dword;
          threadAttr    : PSecurityAttributes;
          stackSize     : integer;
          startAddr     : pointer;
          params        : pointer;
          creationFlags : dword;
          var threadId  : dword          ) : dword; stdcall;
         external 'madCHook.dll';

// **********

// this is how your remote function must look like
type TRemoteExecuteFunction = function (params: pointer) : dword; stdcall;

// executes the specified function in the context of another process
// this works only if the function follows some specific rules
// e.g. it must not use global variables, nor Delphi private functions
// only win32 APIs are allowed
// don't use Delphi strings, since they end up in local Delphi function calls
// if "size" > 0, the "params" block will be copied to the other process
// after the remote function is finished, the "params" block is copied back
// so you can use the "params" block for both "in" and "out" parameters
// if "size" = 0, the "params" value is just given into the remote function
function RemoteExecute (processHandle  : dword;
          func          : TRemoteExecuteFunction;
          var funcResult : dword;
          params         : pointer = nil;
          size          : dword   = 0          ) : bool; stdcall;
         external 'madCHook.dll';

// **********

const
  // (un)inject the specified dll into (from) all current and future processes
  // these flags can be used for both UninjectLibrary + InjectLibrary
  ALL_SESSIONS     = $FFFFFFED;  // apps of all sessions
  CURRENT_SESSION  = $FFFFFFEC;  // apps of current session
  CURRENT_USER     = $FFFFFFEB;  // apps of current user

  // the following flags may only be used in combination with the first 3 flags
  SYSTEM_PROCESSES = $10;  // include this flag to include system processes + services
  CURRENT_PROCESS  = $08;  // exclude this flag to exclude injection into yourself

// same as LoadLibrary, but this one is able to load the library into any process
function InjectLibrary  (processHandle: dword; libFileName: pchar;     timeOut: dword = 7000) : bool; stdcall; external 'madCHook.dll' name 'InjectLibraryA';
function InjectLibraryW (processHandle: dword; libFileName: pwidechar; timeOut: dword = 7000) : bool; stdcall; external 'madCHook.dll';

// same as InjectLibrary(CURRENT_SESSION, ...), but you can choose the session
function InjectLibrarySession  (session: dword; systemProcesses: bool; libFileName: pchar;     timeOut: dword = 7000) : bool; stdcall; external 'madCHook.dll' name 'InjectLibrarySessionA';
function InjectLibrarySessionW (session: dword; systemProcesses: bool; libFileName: pwidechar; timeOut: dword = 7000) : bool; stdcall; external 'madCHook.dll';

const
  // stop the "virus" injection effect (can be used for UninjectLibrary only)
  STOP_VIRUS = $FFFFFFFA;

// same as FreeLibrary, but is able to free the library from any process
function UninjectLibrary  (processHandle: dword; libFileName: pchar;     timeOut: dword = 7000) : bool; stdcall; external 'madCHook.dll' name 'UninjectLibraryA';
function UninjectLibraryW (processHandle: dword; libFileName: pwidechar; timeOut: dword = 7000) : bool; stdcall; external 'madCHook.dll';

// same as UninjectLibrary(CURRENT_SESSION, ...), but you can choose the session
function UninjectLibrarySession  (session: dword; systemProcesses: bool; libFileName: pchar;     timeOut: dword = 7000) : bool; stdcall; external 'madCHook.dll' name 'UninjectLibrarySessionA';
function UninjectLibrarySessionW (session: dword; systemProcesses: bool; libFileName: pwidechar; timeOut: dword = 7000) : bool; stdcall; external 'madCHook.dll';

// **********

// which processId belongs to the specified process handle?
// undocumented function, works in all windows 32 bit systems
function ProcessHandleToId (processHandle : dword) : dword; stdcall;
         external 'madCHook.dll';

// find out what file the specified process was executed from
// the file name buffer must have a size of MAX_PATH characters (or more)
function ProcessIdToFileName (processId : dword;
          fileName  : pchar) : bool; stdcall;
         external 'madCHook.dll';

// **********

// is the current process a service/system process?  (win9x -> always false)
function AmSystemProcess : bool; stdcall; external 'madCHook.dll';

// is the current thread's desktop the input desktop?  (win9x -> always true)
// only in that case you should show messages boxes or other GUI stuff
// but please note that in XP fast user switching AmUsingInputDesktop may
// return true, although the current session is currently not visible
// XP fast user switching is implemented by using terminal server logic
// so each fast user session has its own window station and input desktop
function AmUsingInputDesktop : bool; stdcall; external 'madCHook.dll';

// the following two functions can be used to get the session id of the
// current session and of the input session
// each terminal server (or XP fast user switching) session has its own id
// the "input session" is the one currently shown on the physical screen
function GetCurrentSessionId : dword; stdcall; external 'madCHook.dll';
function GetInputSessionId   : dword; stdcall; external 'madCHook.dll';

// **********

// which module called me? works only if your function has a stack frame
function GetCallingModule : dword; stdcall;
         external 'madCHook.dll';

// **********
// global  =  normal  +  "access for everyone"  +  "non session specific"

function CreateGlobalMutex (name: pchar) : dword; stdcall; external 'madCHook.dll';
function   OpenGlobalMutex (name: pchar) : dword; stdcall; external 'madCHook.dll';

function CreateGlobalEvent (name: pchar; manual, initialState: bool) : dword; stdcall; external 'madCHook.dll';
function   OpenGlobalEvent (name: pchar          ) : dword; stdcall; external 'madCHook.dll';

function CreateGlobalFileMapping (name: pchar; size: dword) : dword; stdcall; external 'madCHook.dll';
function   OpenGlobalFileMapping (name: pchar; write: bool) : dword; stdcall; external 'madCHook.dll';

// **********

// convert strings ansi <-> wide
// the result buffer must have a size of MAX_PATH characters (or more)
// please use these functions in nt wide API hook callback functions
// because the OS' own functions seem to confuse nt in hook callback functions
procedure AnsiToWide (ansi: pchar; wide: pwidechar); stdcall; external 'madCHook.dll';
procedure WideToAnsi (wide: pwidechar; ansi: pchar); stdcall; external 'madCHook.dll';

// **********
// ipc (inter process communication) message services
// in contrast to SendMessage the following functions don't crash NT services

type
  // this is how you get notified about incoming ipc messages
  // you have to write a function which fits to this type definition
  // and then you give it into "CreateIpcQueue"
  // your callback function will then be called for each incoming message
  // CAUTION: each ipc message is handled by a seperate thread, as a result
  //          your callback will be called by a different thread each time
  TIpcCallback = procedure (name       : pchar;
          messageBuf : pointer;
          messageLen : dword;
          answerBuf  : pointer;
          answerLen  : dword); stdcall;

// create an ipc queue
// please choose a unique ipc name to avoid conflicts with other programs
// only one ipc queue with the same name can be open at the same time
// so if 2 programs try to create the same ipc queue, the second call will fail
function CreateIpcQueue (ipc      : pchar;
          callback : TIpcCallback) : bool; stdcall;
         external 'madCHook.dll';

// send an ipc message to whomever has created the ipc queue (doesn't matter)
// if you only fill the first 3 parameters, SendIpcMessage returns at once
// if you fill the next two parameters, too, SendIpcMessage will
// wait for an answer of the ipc queue owner
// you can further specify how long you're willing to wait for the answer
// and whether you want SendIpcMessage to handle messages while waiting
function SendIpcMessage(ipc          : pchar;
          messageBuf     : pointer;
          messageLen     : dword;
          answerBuf      : pointer = nil;
          answerLen      : dword   = 0;
          answerTimeOut  : dword   = INFINITE;
          handleMessages : bool    = true    ) : bool; stdcall;
         external 'madCHook.dll';

// destroy the ipc queue again
// when the queue owning process quits, the ipc queue is automatically deleted
// only the queue owning process can destroy the queue
function DestroyIpcQueue (ipc: pchar) : bool; stdcall;
         external 'madCHook.dll';

// **********

implementation

uses madTools;

initialization
  InitTryExceptFinally;
  IsMultiThread := true;
end.

posted @ 2010-06-04 16:54  delphi中间件  阅读(1035)  评论(0编辑  收藏  举报