This optimization can only be done at runtime. Compiler/linker doesn't
know anything about API function entry points. I need the PE loader to
do its job first.
I found a simple way to do it in 22 instructions some data tables and
labels.
The basic idea is I put a label after the call or invoke. Get the
address of that label and adjust the address to the dword after E8.
That address is also stored in a table that will use that address to
figure out the new offset for E8. I also need a table to store the
correct function offset since I cannot count on the oreder of
functions in the IAT. I also make a copy of the IAT, which I may not
need. I'll post my code. Then you can step thru a debugger and see
whats going on. Its first draft however, so it works, but probably
not for every case. I'm thinkig of taking Iczelions tutorial #3(make a
window)are a real example. I'll be using more than kernel32 then.
There are some imports that are never used to help in testing.
The map file:
0001:00000000 __imp__CreateFileA@28 00401000 -12
kernel32:KERNEL32.dll
0001:00000004 __imp__ExitProcess@4 00401004 -8
kernel32:KERNEL32.dll
0001:00000008 __imp__VirtualAlloc@16 00401008 -4
kernel32:KERNEL32.dll
0001:0000000c __imp__Beep@8 0040100c -0
kernel32:KERNEL32.dll
my edit^
..XMM
..686p
..MMX
..model flat,stdcall
option casemap:none
option proc

ublic
option dotname
assume cs:FLAT,ds:FLAT,ss:FLAT,fs:NOTHING
_TEXT SEGMENT PUBLIC PARA FLAT 'CODE'
_TEXT ENDS
_DATA SEGMENT PUBLIC PARA FLAT 'DATA'
_DATA ENDS
public mainCRTStartup
externdef _imp__Beep@8:NEAR
externdef _imp__CreateFileA@28:NEAR
externdef _imp__ExitProcess@4:NEAR
externdef _imp__VirtualAlloc@16:NEAR
LCALL@4 TYPEDEF proto :dword
FCALL@4 TYPEDEF PTR LCALL@4
LCALL@8 TYPEDEF proto :dword,:dword
FCALL@8 TYPEDEF PTR LCALL@8
$Beep TEXTEQU <LCALL@8 PTR __imp__Beep@8>;E8 optimzed call
Beep TEXTEQU <FCALL@8 PTR _imp__Beep@8> ;FF function pointer call
$ExitProcess TEXTEQU <LCALL@4 PTR __imp__ExitProcess@4>;E8 optimzed call
ExitProcess TEXTEQU <FCALL@4 PTR _imp__ExitProcess@4>;FF function
pointer call
;///////////////////////////////////////////////////////////////////////////////
;// The IAT segment stores the import table address of declared
;// functions. This is used by GetImportEntry to get the function
entry
;// points and store these in a buffer in the same order as in the
;// import table.
;///////////////////////////////////////////////////////////////////////////////
_DATA SEGMENT
align 16
INDEXSIZE=4
NUMINDEX=(IATend/INDEXSIZE)
IATINDEXE=(NUMINDEX*INDEXSIZE)-4
IAT:
__imp__CreateFileA@28:
dd _imp__CreateFileA@28
__imp__ExitProcess@4:
dd _imp__ExitProcess@4
__imp__VirtualAlloc@16:
dd _imp__VirtualAlloc@16
__imp__Beep@8:
dd _imp__Beep@8
IATend=$-IAT
_DATA ENDS
;///////////////////////////////////////////////////////////////////////////////
;// The RELOC segment creates a table to store the function entry
points
;// obtained by GetImportEntry in a buffer in the same order as the
import
;// table. It is filled highest to lowest address.
;///////////////////////////////////////////////////////////////////////////////
_DATA SEGMENT
align 16
RELOC:
Ientry dd 32 dup (0) ;Default 32 redirections
_DATA ENDS
;///////////////////////////////////////////////////////////////////////////////
;//The MAP segment defines a table that stores the call address to be
;//modified and an index to the proper entry point in the IMPORT
segment.
;//The MAP format is:
;//
;// dd address to be changed-1
;// dd function index
;//
;//Order of MAP elements does not matter. The index resolves the
correct
;//function. The index is maually entered.
;///////////////////////////////////////////////////////////////////////////////
_DATA SEGMENT
align 16
MAPITEMSIZE=8 ;Size in bytes of a MAP entry
MAPITEMNUM=(MAPend/MAPITEMSIZE) ;Number of functions to modify
MAPSIZE=(MAPITEMSIZE*MAPITEMNUM) ;Total size of MAP
MAP: ;Function address MAP+0
dd offset .1_Beep-1
TARGET: ;Function index address MAP+4
dd -0
dd offset .1_ExitProcess-1 ;Function address MAP+8
dd -8 ;Function index address MAP+12
MAPend=$-MAP
_DATA ENDS
;///////////////////////////////////////////////////////////////////////////////
;// The code:
;///////////////////////////////////////////////////////////////////////////////
_DATA SEGMENT
align 16
mainCRTStartup:
;////GetImportEntry/////////////////////////////////////////////////////////////
mov ecx,SIZEOF Ientry/4 ;Size of RELOC buffer in DWORDs
mov edx,RELOC[SIZEOF Ientry/4] ;Start with highest address of RELOC
mov eax,IAT[IATINDEXE] ;IATINDEXE sets eax to the end of IAT
mov eax,[eax] ;Get real import table address
GetImportEntry:
mov ebx,[eax] ;Get entry point
mov [edx],ebx ;Store address in RELOC, high to low address
sub eax,4 ;Decrement import table pointer
sub edx,4 ;Decrement RELOC table pointer
sub ecx,4 ;Decrement loop count
jnz GetImportEntry
;////FixCallTarget/////////////////////////////////////////////////////////////
mov ebx,SIZEOF MAPSIZE
lea eax,RELOC[SIZEOF Ientry/4] ;Load highest address of RELOC
FixCallTarget:
mov ecx,dword ptr MAP[ebx-MAPITEMSIZE] ;Address to modify
mov edx,dword ptr TARGET[ebx-MAPITEMSIZE];Index to correct target
function
add edx,eax ;Add RELOC address offset to index
mov esi,[edx] ;Index resolved entry point target
mov edi,ecx ;Address to modify
sub edi,esi
not edi ;Need negative offset
mov [ecx-3],edi ;Put relative offset DWORD after the E8
sub ebx,8
jnz FixCallTarget
;//////////////////////////////////////////////////////////////////////////////
invoke $Beep,0,0
..1_Beep::
invoke Beep,0,0
invoke $ExitProcess,0
..1_ExitProcess::
ret
_DATA ENDS
end
!!!8 space tabs make formatting a nightmare!!!
Any advice to make this better appreciated.
Thanks.