Link to home
Start Free TrialLog in
Avatar of Blacksoulman
Blacksoulman

asked on

Api Spying

Im trying to make one function that will work for all hooked apis in the iat.
Heres what i want to do.

Save original api address so i can call it later. Replace original api address with my own function address.

Now when an api is called it jumps to that ONE function address.
Call the original api i saved somewhere(hardpart). How and where would i save this address?
ret

Ok the question is not how do i patch the iat.  I know how to do that.

It is what this ONE "dummy" function should do in order to call the original api and work for ALL apis in the iat.  Something like...
 
Procedure GenericHookProc;stdcall;
begin
 asm
  //call original api that i saved somewhere <<how do i do this?
  //get the api function name
  ret //resume code in the module
 end;
end;

Oh and if any of you know of an api spy that works for SYSTEM process in XP lemme know.  None out there work for SYSTEM processes, that ive seen.
Avatar of Russell Libby
Russell Libby
Flag of United States of America image

Ok...
I will offer my "humble" opinion on this, but others (ie: Madshi, etc) could probably offer more input on this....

Patching the IAT (at least for statically linked dll's) is easy. When an API call is made to one of the api's, a relative CALL is made to the IAT for the dll, and then an absolute JMP is made to the actual function address.

do api ----> IAT ----> JMP absolute to API ... RET

So, in a normal hook, you would save off the 6 bytes that make up this instruction into memory (allocated via virtual alloc, with PAGE_EXECUTE_READWRITE permissions). You then replace the 5/6 bytes with the relative/absolute jump to your hooking function address.

do api ----> IAT ----> JMP hook function

Now the problem (as I'm sure you have realized) is this. How to figure out (in your scenario) which IAT index was actually called, then redirected to your hooking function?? You have a many-to-one relationship with your hook, which makes this VERY difficult.

If it was me, when creating a jump to the hook, I would do the following (creating instructions in the memory block for the hook):

In the IAT, rewrite the code to JMP absolute to the "patch" code block (memory) you have allocated for your "patch". In that "patch" memory block, add 11/12 bytes of code which amount to:

call {address of hooking function relative from this memory} // 5 bytes
     // Could also be 6 bytes, jmp absolute to the hooking function
jmp {absolute index retrieved from the IAT} // 6 bytes

do api ----> IAT ----> JMP "patch block" ---> call Hook --> JMP absolute API

This will let your hook function be called when any of the hooked address in the IAT are called. Problem is, it tells you nothing about "which" function was called. Plus, I believe you may have to be careful about preserving the registers in your hook (have to read the Intel manuals again regarding CALL), because you have no idea how many will be required by the actual api call itself. The only thing this does is redirect the IAT to your your "patch" code block in memory --> then to your hook --> then to the actual API call.

You COULD extend this further, and PUSH the EAX register, move the absolute address from the IAT to EAX (Or,  push the index of the IAT call), call your hook, pop EAX, and then finally jump to the old IAT address:

eg

push EAX // 1 byte
mov  EAX, {absoulte address from the IAT / Index of IAT call}
call {address of hooking function relative from this memory} // 5 bytes
     // Could also be 6 bytes, jmp absolute to the hooking function
pop  EAX // 1 byte
jmp {absolute index retrieved from the IAT} // 6 bytes

Your hooking function should then be written to recieve a pointer (or integer of IAT index). Also, get rid of the stdcall; its already handled by the code generation (cleanup). The function should have no calling conventions added to it, leaving it as register.

procedure GenericHookProc(Func: Pointer);
// or procedure GenericHookProc(FuncIndex: Integer);
asm
   // Original api will be called after we return from this procedure
   ret
end;

Anyways, this it just my suggestion/idea, and I'm sure others probably know **much** more than I do regarding this, so I would wait for other experts to offer their input.

If you want though, I can take a look at putting this (the suggestions) to actual code in the morning.

Hope this helps some,
Russell
Avatar of Blacksoulman
Blacksoulman

ASKER

Thank you. Im starting to digest it especially that last part because i was already thinking of passing some parameter related to the old api to my hook function by pushing an extra parameter on the old api stack(eax).  And then when it jmps to my code block pop eax back off and call the api.  Is this what you were saying?  If not where are you putting the apiindex or func pointer.


  I am by far no asm guru at all.  So if anyone has any more ideas im going to need to see the code, with comments, because im not sure i could implement it myself.

Well, if you are no asm guru, you should better forget doing this...   :-)   Hooking APIs without knowing how many parameters and which calling convention the APIs have is quite difficult. As Russell said, you need to make sure that the registers stay correct. Also you must not change the stack, cause some parameters may lie there, too. All this stuff is only possible by writing asm code very carefully.
ASKER CERTIFIED SOLUTION
Avatar of Russell Libby
Russell Libby
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
i will give you points but im just wondering how else i could spy on all apis besides a centralized hooked procedure and a hook function for each api?

Well... this IS about the only way. (Short of declaring seperate hook functions for each api call you wanted to hook).

If you take a look at the code I gave you, it does a CALL (vs JMP) to the generic hook procedure, so I ** believe** you should be ok in regards to the stack and registers. Also, I hope the "patch" code makes sense now, and why it is needed. Without it, eg: if the redirection from the api call just entered into your generic hook function, you would have a hard time:

1.) Figuring out where the call came from.
2.) Where the jmp needs to go.

Using the code above, you could use a TList or other suitable container to store record/code information you build up while walking an IAT for a module. You could also split the EAX register into a high/low word; storing the module index (hopefully you would never have more than 65535) in one part, and the function index in the other.

Just some thoughts,
Russell


alright just a follow up question

everything works fine up until
 Pointer(Pointer(Pointer(@lpCode^[2])^)^):=PatchTable[dwIndex].lpPatchAddr;

here it crashes and im not really sure what this is for anyway. I mean youve already used lpcode[2] with MoveMemory(@lpCode^[2], @dwIndex, 4);

So, if i leave this line out it calls the patch address in memory and the GenericHookProc but doesnt call the original function.
Sorry for the delay in responding....

1.) What is the "crash" exactly? I am guessing that you mean an exception; perhaps you could elaborate further. Also, can you add a check for the result of VirtualProtect(...) which is called right before to make sure that it is succeeding.

2.) lpCode WAS used previously, but if you check the code again, you will see that the pointer var is reset before being used in this scenario.

      // Set the absolute jump in the IAT to our patch memory
      lpCode:=lpBase[dwIndex];  <----- Set to new address
      VirtualProtect(lpCode, 6, PAGE_EXECUTE_READWRITE, dwProtect);
      Pointer(Pointer(Pointer(@lpCode^[2])^)^):=PatchTable[dwIndex].lpPatchAddr;

This is the jump to the old (original function), which is why it is not getting called if you leave this piece out. Anyways, let me know the result of (1) above and I can help you further.

Russell
i couldnt find any contact info for you whatsoever .  Do you have a website or email address youd be willing to share?

ok i use this for the lpBase instead:

ImportCode := Pointer(dword(ImageDosHeader) + ImageImportEntry^.FirstThunk);//VA of function

So i dont need the array of apis.  What do i put in place of lpBase[] ?  If i already have the address from the ImageDescriptor.  I tried something like this.

PatchTable[dwIndex].lpAddr:= ImportCode;//old api address
//i don't know what to put in place for this..
PatchTable[dwIndex].lpApiAddr:=Pointer(Pointer(Pointer(@PByteArray(lpBase[dwIndex])^[2])^)^);//what is at [2]??  The third api pointer?
I already stored the old api address in lpAddr.  So i set everything that used lpAddr with ImportCode. At the end it looks like
ImportCode^ := lpCode;//old api address now points to patch mem
VirtualProtect(lpCode, 6, PAGE_EXECUTE_READWRITE, dwProtect);
 Pointer(Pointer(Pointer(@lpCode^[2])^)^):=PatchTable[dwIndex].lpPatchAddr;
//dont know what do with this last line either.

What exactly is at the 3rd byte of lpCode?  

And since i cant list every function manually i tried to get the import name table.  I opened another question here:  https://www.experts-exchange.com/questions/20925997/Import-Name-Table.html
those points are waiting for you. :)
alright i dont know how the other answer solves my question to this one.

Is the return address of the api function at lpcode[2]?  I took off one of the pointer() in both and it didnt crash but it didnt do anything either.

Blacksoulman,

I have really been swamped which has made it hard to find "free" time to keep doing further research with this question, but I do want to address your questions.

First, the example code I gave you made use of the IAT, but in an indirect way. (If you already know this stuff, then I apologize, but your questions have been in regards to the code at [2]..).

You already know the IAT is a pointer to an array of pointers, for example (example only):

IAT - > of $00442274

$00442274 [$77E7A29B]  // GetTickCount
$00442278 [.........]  // GetVerison
 ...      [.........]

The example code was extracting the IAT info through the use of the function address's, which translate to this in the exe.

@GetTickCount = FF2570224400 // 6 bytes of code in memory
Translated to asm, this is:

JMP DWORD PTR [$00442274]

So my code was skipping the 2 bytes that make up the absolute jump. The remaining 4 bytes make up the address of the IAT entry. (which hold the actual function address). The code then cast lpCode[2] (3rd byte) as a PByteArray, then as Pointer, to get the contents of the IAT memory, which in this case is the actual function address of $77E7A29B. The contents are then replaced with the patch code memory.

So, leading on....
I have spent some time working with IAT parsing. At first I tried to use the FindFirst/Next that I gave you, but then realized that some function/library names get duped, thus I ended up double-hooking them. Not pretty ;-). So I revamped a unit to handle the IAT info in a somewhat more elegant fashion. Plus, it is able to check to see if a function has already been hooked by determining if the GetProcAddress is the same as what the the IAT^ contents hold. I also added a hooking function in there as well.

Now to your problem....

I have revamped the code to hook by modifiying the IAT directly. One note though: this should probably not be done on the system dlls for Win95/98/ME systems. (I'm hoping that Madshi would be willing to offer his expert advise on this?, for points of course).

Also, it is also not advisable to hook EVERY imported function call, as your generic hook might end up being called infinitely if something in the hook used an api that was hooked. For example, say you hooked MessageBox and then called MessageBox in the GenericHookProc. Oops ;-). You get the drift I'm sure....

Anyways, that is why the IAT code I did was pertinent to this. With the IAT code, I/you have the ability to walk all imported dlls, as well as their functions, by NAME no less.

If you have any other questions/problems then let me know, and I apologize ahead of time for any delays in my future responses.

Regards,
Russell

----

unit IAT;
////////////////////////////////////////////////////////////////////////////////
//   IAT utility functions
////////////////////////////////////////////////////////////////////////////////
interface

uses
  Windows, SysUtils, Classes;

////////////////////////////////////////////////////////////////////////////////
//   Data Types
////////////////////////////////////////////////////////////////////////////////
type
  IndirectAddr         =  ^Pointer;

////////////////////////////////////////////////////////////////////////////////
//   Import description info structure
////////////////////////////////////////////////////////////////////////////////
type
  PImageImportDesc     =  ^TImageImportDesc;
  TImageImportDesc     =  packed record
     FuncNameList:     DWORD;
     TimeDateStamp:    DWORD;
     ForwarderChain:   DWORD;
     Name:             DWORD;
     FirstThunk:       DWORD;
  end;

////////////////////////////////////////////////////////////////////////////////
//   Visible functions from this unit
////////////////////////////////////////////////////////////////////////////////
function   IsIATInfoLoaded: Boolean;
function   LoadIATInfo: Boolean;
function   UnloadIATInfo: Boolean;
function   GetIATLibraryCount: Integer;
function   GetIATFunctionCount(LibraryName: String): Integer;
function   GetIATLibraries(List: TStrings): Boolean;
function   GetIATFunctions(LibraryName: String; List: TStrings): Boolean; overload;
function   GetIATFunctions(LibraryIndex: Integer; List: TStrings): Boolean; overload;
function   GetIATFunctionAddr(LibraryName, FunctionName: String): IndirectAddr;
function   IsIATFunctionHooked(LibraryName, FunctionName: String): Boolean;
function   HookIATFunction(LibraryName, FunctionName: String; NewFunction: Pointer): Boolean;

implementation

////////////////////////////////////////////////////////////////////////////////
//   Protected variables
////////////////////////////////////////////////////////////////////////////////
var
  Libraries:     TStringList =  nil;
  Loaded:        Boolean     =  False;

// Helper function for parsing name tables
function NextFunctionName(lpName: PChar): PChar;
begin

  result:=StrEnd(lpName);
  while (result^ = #0) do Inc(result);

end;

// Determines if IAT info has already been loaded
function IsIATInfoLoaded: Boolean;
begin

  // Return loaded state
  result:=Loaded;

end;

// Get the count of imported libraries
function GetIATLibraryCount: Integer;
begin

  // Make sure we are loaded
  if not(Loaded) then LoadIATInfo;

  // Result is the count of libraries
  result:=Libraries.Count;

end;

// Hook the IAT by installing a new function pointer into the table
function HookIATFunction(LibraryName, FunctionName: String; NewFunction: Pointer): Boolean;
var  lpIAT:      IndirectAddr;
     dwProtect:  DWORD;
begin

  // Get the IAT address first
  lpIAT:=GetIATFunctionAddr(LibraryName, FunctionName);

  // Check IAT address
  if Assigned(lpIAT) then
  begin
     // Unprotect so we can modify it
     if VirtualProtect(lpIAT, SizeOf(lpIAT^), PAGE_EXECUTE_READWRITE, dwProtect) then
     begin
        // Set the new function address
        lpIAT^:=NewFunction;
        // Reset the memory protection
        VirtualProtect(lpIAT, SizeOf(lpIAT^), dwProtect, dwProtect);
        // Flush the instruction cache
        FlushInstructionCache(GetCurrentProcess, nil, 0);
        // Success
        result:=True;
     end
     else
        // VirtualProtect failed
        result:=False;
  end
  else
     // Failed to get IAT
     result:=False;

end;

// Determine if the function has been hooked
function IsIATFunctionHooked(LibraryName, FunctionName: String): Boolean;
var  lpIAT:      IndirectAddr;
     hMod:       THandle;
begin

  // Get the IAT address first
  lpIAT:=GetIATFunctionAddr(LibraryName, FunctionName);

  // Check assignment
  if Assigned(lpIAT) then
  begin
     // Now we need to get the proc address and check against IAT contents.
     // Notes: from what I understand, this will not work for Win95/98/Me, so
     // be forewarned.
     hMod:=GetModuleHandle(PChar(LibraryName));
     // Check module handle
     if (hMod = 0) then
        // Should have been loaded
        result:=False
     else
         // Perform check
         result:=not(GetProcAddress(hMod, PChar(FunctionName)) = lpIAT^);
  end
  else
     // Address is nil
     result:=False;

end;

// Get the IAT function address for the specified function
function GetIATFunctionAddr(LibraryName, FunctionName: String): IndirectAddr;
var  Functions:        TStringList;
     dwIndex:          Integer;
begin

  // Make sure we are loaded
  if not(Loaded) then LoadIATInfo;

  // Set default result
  result:=nil;

  // Find the library first
  if Libraries.Find(LibraryName, dwIndex) then
  begin
     // Get the function list
     Functions:=Libraries.Objects[dwIndex] as TStringList;
     // Check list assignment
     if Assigned(Functions) then
     begin
        // Find the function name
        if Functions.Find(FunctionName, dwIndex) then
        begin
           // Found the function, get the IAT pointer
           result:=Pointer(Functions.Objects[dwIndex]);
        end;
     end;
  end;

end;

// Get the list of imported functions for the library at the given index
function GetIATFunctions(LibraryIndex: Integer; List: TStrings): Boolean;
begin

  // Make sure we are loaded
  if not(Loaded) then LoadIATInfo;

  // Check the index
  if (LibraryIndex < 0) or (LibraryIndex > Pred(Libraries.Count)) then
     // Invalid index specified
     result:=False
  else
     // Call the other GetIATFunctions
     result:=GetIATFunctions(Libraries[LibraryIndex], List);

end;

// Get the function count for the library
function GetIATFunctionCount(LibraryName: String): Integer;
var  Functions:        TStringList;
     dwIndex:          Integer;
begin

  // Make sure we are loaded
  if not(Loaded) then LoadIATInfo;

  // Attempt to find the library name
  if Libraries.Find(LibraryName, dwIndex) then
  begin
     // Get the function list
     Functions:=Libraries.Objects[dwIndex] as TStringList;
     // Return count from function list
     result:=Functions.Count;
  end
  else
     // Library not found
     result:=(-1);

end;

// Get the list of imported functions for the specified library
function GetIATFunctions(LibraryName: String; List: TStrings): Boolean;
var  Functions:        TStringList;
     dwIndex:          Integer;
begin

  // Make sure we are loaded
  if not(Loaded) then LoadIATInfo;

  // Attempt to find the library name
  if Libraries.Find(LibraryName, dwIndex) then
  begin
     // Get the function list
     Functions:=Libraries.Objects[dwIndex] as TStringList;
     // Check list assignment
     if Assigned(List) and Assigned(Functions) then
     begin
        // Fill in the passed list
        List.Clear;
        List.AddStrings(Functions);
        // Success
        result:=True;
     end
     else
        // List or Functions was nil
        result:=False;
  end
  else
     // Library name not founc
     result:=False;

end;

// Get the list of imported libraries
function GetIATLibraries(List: TStrings): Boolean;
begin

  // Make sure we are loaded
  if not(Loaded) then LoadIATInfo;

  // Check list assignment
  if Assigned(List) then
  begin
     // Fill in the passed list
     List.Clear;
     List.AddStrings(Libraries);
     // Success
     result:=True;
  end
  else
     // List was nil
     result:=False;

end;

// Unloads the IAT information and releases all allocated memory
function UnloadIATInfo: Boolean;
var  dwIndex:    Integer;
begin

  // Check loaded state
  if Loaded then
  begin
     // Iterate the libraries and free all function lists
     for dwIndex:=Pred(Libraries.Count) downto 0 do
     begin
        Libraries.Objects[dwIndex].Free;
     end;
     // Free the library list
     Libraries.Free;
     Libraries:=nil;
     // Turn loaded state off
     Loaded:=False;
  end;

  // Result is the reverse of the loaded state
  result:=not(Loaded);

end;

// Loads the IAT information for the process
function LoadIATInfo: Boolean;
var  ImageNTHeaders:   PImageNtHeaders;
     ImageDosHeader:   PImageDosHeader;
     ImageDesc:        PImageImportDesc;
     Functions:        TStringList;
     lpIAT:            IndirectAddr;
     lpszName:         PChar;
     dwEndDesc:        DWORD;
     dwIndex:          Integer;
begin

  // Are we already loaded
  if not(Loaded) then
  begin
     // Create list for libraries
     Libraries:=TStringList.Create;
     with Libraries do
     begin
        Sorted:=True;
        Duplicates:=dupIgnore;
     end;
     // Get start of PE32 header and NT header
     ImageDosHeader:=Pointer(GetModuleHandle(nil));
     ImageNTHeaders:=Pointer(Integer(ImageDosHeader)+ImageDosHeader^._lfanew);
     // Get import entry description and ending point for imports
     with ImageNTHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] do
     begin
        ImageDesc:=Pointer(DWORD(ImageDosHeader)+VirtualAddress);
        dwEndDesc:=VirtualAddress+Size;
     end;
     // Check import entry
     if Assigned(ImageDesc) then
     begin
        // Last item in the entry will be null
        while (ImageDesc^.Name > 0) do
        begin
           // Check offsets
           while (ImageDesc^.FirstThunk <= dwEndDesc) and (ImageDesc^.FirstThunk > 0) do
           begin
              // Get the libary name and see if it has already been added
              lpszName:=PChar(DWORD(ImageDosHeader)+ImageDesc^.Name);
              // Check libraries list
              if not(Libraries.Find(lpszName, dwIndex)) then
              begin
                 // Create list to hold the function names for the library
                 Functions:=TStringList.Create;
                 with Functions do
                 begin
                    Sorted:=True;
                    Duplicates:=dupIgnore;
                 end;
                 // Add the library name and function list to the libraries list
                 dwIndex:=Libraries.AddObject(lpszName, Functions);
              end;
              // Get the function list from the libraries list
              Functions:=Libraries.Objects[dwIndex] as TStringList;
              // Get the start of the IAT table
              lpIAT:=Pointer(DWORD(ImageDosHeader)+ImageDesc^.FirstThunk);
              // Iterate the IAT table
              while Assigned(lpIAT) and Assigned(lpIAT^)do
              begin
                 // Get the function name
                 lpszName:=NextFunctionName(lpszName);
                 // Has this function already been added?
                 if not(Functions.Find(lpszName, dwIndex)) then
                 begin
                    // Add the function name and the IAT address for the function
                    Functions.AddObject(lpszName, TObject(lpIAT));
                 end;
                 // Get the next IAT entry
                 Inc(lpIAT);
              end;
              // Get the next import library
              Inc(ImageDesc);
           end;
        end;
     end;
     // Done loading
     Loaded:=True;
  end;

  // Result is loaded state
  result:=Loaded;

end;

initialization

  // Set starting defaults
  Libraries:=nil;
  Loaded:=False;

finalization

  // Cleanup
  UnloadIATInfo;

end.

--------------

unit SampleHook;

interface

uses
  Windows, SysUtils, Classes, IAT;

////////////////////////////////////////////////////////////////////////////////
// Record to hold patch information (forms a singly linked list)
////////////////////////////////////////////////////////////////////////////////
const
  MAX_IDENT         =  255;

type
  PPatchRecord      =  ^TPatchRecord;
  TPatchRecord      =  packed record
     lpAddr:        Pointer;
     lpApiAddr:     Pointer;
     lpPatchAddr:   Pointer;
     lpszLib:       Array [0..MAX_IDENT] of Char;
     lpszName:      Array [0..MAX_IDENT] of Char;
     lpNextPatch:   PPatchRecord;
  end;

////////////////////////////////////////////////////////////////////////////////
// Patch code structure
////////////////////////////////////////////////////////////////////////////////
type
  /////////////////////////////////////////////////////
  //
  //    Patch Code layout
  //    -----------------------------------------------
  //    1 BYTE(s)   :  PUSH  EAX
  //    5 BYTE(s)   :  MOV   EAX, [Pointer of Patch Record]
  //    6 BYTE(s)   :  CALL  dword ptr [@PatchCode[20]]
  //    1 BYTE(s)   :  POP   EAX
  //    6 BYTE(s)   :  JMP   dword ptr [@PatchCode[24]]
  //
  //    PatchCode[20]  =  @GenericHookProc
  //    PatchCode[24]  =  @Actual Api Function
  //
  /////////////////////////////////////////////////////
  PPatchCode        =  ^TPatchCode;
  TPatchCode        =  packed record
     Code:          Array [0..31] of Byte;
  end;

////////////////////////////////////////////////////////////////////////////////
// Generic hook proc to recieve the redirected call from any of the
// hooked api calls (must be a register call ONLY)
////////////////////////////////////////////////////////////////////////////////
procedure GenericHookProc(PatchRecord: PPatchRecord);

////////////////////////////////////////////////////////////////////////////////
// Global variables
////////////////////////////////////////////////////////////////////////////////
var
  // Patch list head node
  lpPatchHead:      PPatchRecord   =  nil;

////////////////////////////////////////////////////////////////////////////////
// Hooking functions
////////////////////////////////////////////////////////////////////////////////
function   HookIAT: Boolean;
function   UnhookIAT: Boolean;

implementation

var
  bHooked:          Boolean  =  False;

////////////////////////////////////////////////////////////////////////////////
//   Example of hooking all functions from kernel32.dll that start with "G"
////////////////////////////////////////////////////////////////////////////////
function HookIAT: Boolean;
var  Functions:        TStringList;
     lpIAT:            IndirectAddr;
     lpPatch:          PPatchRecord;
     lpCode:           PByteArray;
     dwCount:          Integer;
     dwOffset:         Integer;
begin

  // Check hook state
  if not(bHooked) then
  begin
     // Get the functions for kernel32.dll
     Functions:=TStringList.Create;
     if GetIATFunctions('kernel32.dll', Functions) then
     begin
        // Walk the function list
        for dwCount:=0 to Pred(Functions.Count) do
        begin

           // Check the function name
           if (Functions[dwCount] = '') then Continue;
           if (Functions[dwCount][1] <> 'G') then Continue;

           // Get the IAT for the function
           lpIAT:=GetIATFunctionAddr('kernel32.dll', Functions[dwCount]);
           if not(Assigned(lpIAT)) then Continue;

           // Allocate a new patch record and put it on to the head of the list
           lpPatch:=AllocMem(SizeOf(TPatchRecord));
           lpPatch^.lpNextPatch:=lpPatchHead;
           lpPatchHead:=lpPatch;

           // Set the patch table fields
           StrPCopy(@lpPatch^.lpszLib, 'kernel32.dll');
           StrPCopy(@lpPatch^.lpszName, Functions[dwCount]);
           lpPatch^.lpAddr:=lpIAT;
           lpPatch^.lpApiAddr:=lpIAT^;

           // Allocate patch memory
           lpPatch^.lpPatchAddr:=VirtualAlloc(nil, SizeOf(TPatchCode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);

           // Build the instruction codes for the patch
           lpCode:=lpPatch^.lpPatchAddr;

           // We want to pass the PatchRecord into the hook function so we
           // can determine why the hook was called.
           //
           // PUSH  EAX
           // MOV   EAX, lpPatch
           //
           lpCode^[0]:=$50;
           lpCode^[1]:=$B8;
           dwOffset:=Integer(lpPatch);
           MoveMemory(@lpCode^[2], @dwOffset, 4);

           // Now generate the call to the GenericHookProc
           //
           // CALL  DWORD PTR [GenericHookProc]
           //
           lpCode^[6]:=$FF;
           lpCode^[7]:=$15;
           Pointer(Pointer(@lpCode^[20])^):=@GenericHookProc;
           dwOffset:=Integer(@lpCode^[20]);
           MoveMemory(@lpCode^[8], @dwOffset, 4);

           // Now we need to pop EAX so the stack is restored
           //
           // POP   EAX
           lpCode^[12]:=$58;

           // Now we need to call the original API function address
           //
           // JMP   DWORD PTR [ApiAddress]
           //
           Pointer(Pointer(@lpCode^[24])^):=lpPatch^.lpApiAddr;
           dwOffset:=Integer(@lpCode^[24]);
           lpCode^[13]:=$FF;
           lpCode^[14]:=$25;
           MoveMemory(@lpCode^[15], @dwOffset, 4);

           // Finally we need to hook the IAT entry for this function
           // so it will call our patch memory, instead of the API address
           //
           HookIATFunction(lpPatch^.lpszLib, lpPatch^.lpszName, lpPatch^.lpPatchAddr);

        end;
     end;
    // Free the function list
     Functions.Free;
     // Now hooked
     bHooked:=True;
  end;

  // Set result
  result:=bHooked;

end;

function UnhookIAT: Boolean;
var  lpPatch:          PPatchRecord;
begin

  // Return result based on state
  result:=bHooked;

  // Are we hooked?
  if bHooked then
  begin
     // Unhook all functions
     while Assigned(lpPatchHead) do
     begin

        // Get the function from top of the linked list and relink
        lpPatch:=lpPatchHead;
        lpPatchHead:=lpPatch^.lpNextPatch;

        // Replace the IAT contents with the old function address
        HookIATFunction(lpPatch^.lpszLib, lpPatch^.lpszName, lpPatch^.lpApiAddr);

        // Dispose of the patch record patch memory
        VirtualFree(lpPatch^.lpPatchAddr, 0, MEM_RELEASE);

        // Dipose of the patch record
        FreeMem(lpPatch);

     end;
     // Remove the hooking flag
     bHooked:=False;
  end;

end;

procedure GenericHookProc(PatchRecord: PPatchRecord);
begin

  MessageBox(0, PatchRecord^.lpszName, nil, MB_OK);

end;

initialization

  // Set state
  bHooked:=False;

finalization

  // Unhook if hook state is set
  if bHooked then UnhookIAT;

end.
"Ok the question is not how do i patch the iat.  I know how to do that. "

I said this so people wouldnt have to rewrite code to walk the iat.  

You answered my last question in the first part of your comment.  I did not want to make you write all that.  Im already using afxCodeHook to walk the iat.  All i needed to know was that the actual api address was at [2].  When i understood that i was able to get it with getprocaddress() with the import function names.  

But thank you anyway.  Im sure whoever reads this will be practically an expert at the PE.
PS.  Where is your contact info??!!

Sorry the code was overkill, but I didn't want to make assumptions on what you were using code wise/your experience level/etc. No offense meant, ok...

And, I will probably get in trouble for this (EE site wise, I don't think they like it too  much)... but:

russell_dana@msn.com

No site, no nada, just an e-addr. Like to keep a semi-lo profile. Not that it's a big secret, as I did provide my contact info with a dissasembly conversion that is available at Programmer's Heaven:

http://www.programmersheaven.com/zone2/cat529/32918.htm

It is not as elegant as what Madshi has done, but it does a pretty decent job at disassembling memory instructions to something understandable (ie: easily recognized as what is seen in the Delphi CPU window). Not that I'm pushing it btw ;-), just though it might interest you as well.

Anyways, hope all is good, and I hope I have answered your question(s) to your satisfaction.

Kind Regards,
Russell
> this should probably not be done on the system dlls for Win95/98/ME systems.

That's right. In win9x you should skip all modules above $80000000. But you should also skip all modules below $80000000 which have a shared IAT! Most people are missing that fact when doing IAT patching, which can result in OS instability.