Log in

View Full Version : Import Address Table patching


SmallMan
December 17th, 2002, 15:18
I'm trying to modify the behaviour of a kernel API function in a Win32 program.

So far I've created a DLL containing all of the functions the program imports from KERNEL32 (Obviously changing their names slightly), and each function calls the original function from the kernel with the exception of the one I'm trying to modify. I patched this new DLL into the program's Import Address Table by simply overwriting the KERNEL32 entry (They are the same length).

However, whenever I then try to run the program, I get an access violation. Is there something I've missed? Are certain kernel functions "tied" to the code that uses them in a special way? Is it naive of me to declare ANSI parameter-based functions with original non-resolved declaration in my DLL? Is there a simpler way to modify 1 function?

nikolatesla20
December 17th, 2002, 15:43
Just a little more info ?

How did you compile your DLL? Win32 system DLLS are stdcall, so make sure you are declaring stdcall functions, or your stack will be hosed and you'll GPF.

Also, um, what do you mean you changed their names slightly....if you did that the entire IAT table would need to be changed, not just the DLL name entry.

You could also patch in a call to your own DLL quite easily by editing the IAT table manually and adding a new DLL entry. (In other words, add your DLL name reference, and then change the IAT table to point to the function name in that DLL instead). But this would be only if you were familiar with the IAT structures well enough.

-nt20

SmallMan
December 17th, 2002, 16:08
I didn't explicity declare them as stdcall, no. That's not the default?

By changing the names slightly, I mean:-

GetTickCount

becomes

KetTickCount (K for KERNEL32) in the IAT, and a matching function is in my DLL, which returns GetTickCount(). The length of the names doesn't change. Where the names would be duplicate (For example GetCurrentDirectoryA and SetCurrentDirectoryA) I change the second character of one of them to E, and so on.

A restriction placed on what I can do is that the file size must not change. I've read a page about adding my DLL separately to the imports, but that would increase the file size.

I'd say I know the PE image structure fairly well (I wrote a program that changes the data, I don't do it manually, sticks in my head better that way).

JimmyClif
December 17th, 2002, 18:02
/me is scratching my head....

You patched all the functions from Kernel32.dll so that they have different names.. then you created a dll with the real names which have the real names of the functions pointing to the renamed ones...

One problem is that Kernel32.dll always needs to have the 'thing' corrected... Checksum.. there we go... maybe you forgot about that... Use Pe-Sum for that... (protools)

Other thing is... why if you just want to modify 1 single function aren't you using a Hook for that ? Or patch Kernel32.dll at the function you want to take over pointing to your Dll ?

nikolatesla20
December 17th, 2002, 18:09
If you are using VC++:

Go to the Project settings dialog

Go to C++ tab

Under the drop down box, select "Code generation".

Under "Calling convention" select "__stdcall". It's __cdecl by default in a win32 DLL project.

Save the project.

NOW

Names will usually get decorated with crap. You will see this if you open your dll in the dependency viewer. Exported functions will be decorated with extra characters. To avoid this, make a *.def file for the DLL.

NOW don't let somebody here fool you that you don't need the next step below! YOU DO. You can use _declspec to declare the function for exporting, but it will get DECORATED. If you use a DEF file, it won't. We don't want it to be decorated. SO use a DEF file. (If you use a DEF file, you don't need to declare _declspec or anything like that at all.)

Now, Go to "Project -> add files to project" and select a text file. Name it <your dll name>.def

In the def file, simply type a line that says "EXPORTS"

now put the name you want the exported function to have and then "=" and then the name of the actual function in the DLL.

Example:

Code:

EXPORTS
KessageBox=KessageBox


Then the linker won't decorate the names. It will export the names clean. Otherwise you'll get decoration. (decoration is when the name of the function in the DLL contains extra info about amount of parameters, parameter type, etc, for example, KessageBox could end up being exported as ?KessageBox@@YGHXZ@).

Do this an recompile and it should now work.

-nt20

SmallMan
December 18th, 2002, 00:37
I always use .DEF files, so that's not a problem. If I can alias the function names however, I wouldn't need to change them in the program's IAT. Thanks for that.

A checksum shouldn't come into it. Nothing knows (or should know) that my KERNEL32 replaces the real KERNEL32 and as there's nothing in the imports section of a PE image to flag a "special" DLL, there should be no questions asked.

I don't think directly patching KERNEL32.DLL is an option (An anti-virus program would probably intervene). I could create a copy of the kernel local to the program, but I don't know how to "insert" my function into it.

Just to clarify, the program doesn't crash immediately, just a small way into its initialisation process I get an Access Violation. It makes a few calls, including the one I've changed, at startup, then Sleep, then a few OutputDebugStrings, and then stops. If I debug it with the normal kernel referenced the next thing the debugger notices is the dynamic loading of a DLL.

Woodmann
December 18th, 2002, 01:43
Howdy,

I am also having trouble understanding this but,
I'm not the most intelligent person

Dll's are trying to load into the same space.
Are you sure the import table is correct.

Maybe start over and try the "hook" method.
It seems like a lot of work to change one function.

Later, Woodmann

SmallMan
December 18th, 2002, 02:17
Load into the same space? How could that happen? I thought at run-time the PE loader loads each DLL and then maps them to the image's requirements. Could my DLL be obstructing the real kernel DLL?

Perhaps there's a way to patch the function by writing a program that calls CreateProcess with the program and suspends it, accesses the process's memory and changes it there?

nikolatesla20
December 18th, 2002, 04:18
Actually, smallman, that is usually how it is done (loaders). It's very easy to suspend the created thread and then patch its memory , as long as you know where to patch.

Anyway, I was thinking - if you are getting an error on a loading DLL after a while, then it's a GetProcAddress problem it seems to me. On one hand, it's good the have your DLL have the name "Kernel32.dll" for any cases of GetProcAddress to work right, but this could cause a problem if somehow the system grabs the real kernel32.dll, also kinda dependent on the O.S. you are using - in it's win98, kernel32.dll is in shared memory and will only be loaded once......

I wouldn't think you would want your DLL name to be "kernel32.dll" , it should be something different, but of course then GetProcAddress won't work (if it so happens to be using that to access the ONE function you want to change.)

Well, who knows but I suspect a GetProcAddress problem.

I think it would be a better solution to patch memory at load time. It's very easy to do, since CreateProcess gives you a nice handle to all the information you need.

-nt20

SmallMan
December 18th, 2002, 05:26
I fixed it!!!

Remember:-
Quote:
Originally posted by SmallMan:-
Is it naive of me to declare ANSI parameter-based functions with original non-resolved declaration in my DLL?


I used the proper ANSI-based declarations for all of the "functionA" functions that needed it and voilá. Forgot XP == NT, hence string functions resolve to "functionW", for Unicode.

I'd still like to persue the patching in memory thing, though. Anyone know a good page or two for it?

SmallMan
December 28th, 2002, 02:29
Okay, I've messed about a bit, and this what I've tried to achieve:-

1. Open a program using CreateProcess, using debugger flags and loop to get hold of the PE image base address.

2. Move through the PE structure to the IAT once the initial breakpoint has been hit (That should ensure Windows has written the current addresses to it).

3. Replace the address for a specific function with that present in my program, the program that started the process.

Now, I seem to have run into a bit of trouble with WriteProcessMemory, in that it won't let me overwrite the address in the IAT (GetLastError() == ERROR_NOACCESS). I know there are flags in the characteristics of sections that make them read-only, etc., but how does that work in memory? If it's located on a specific page, can't I unlock it somehow (VirtualProtectEx) ?

nikolatesla20
January 6th, 2003, 16:00
Not sure why you get that error, I've had no problem writing anywhere into a process when created with DEBUG flag using CreateProcess- make sure you are using OpenProcess() before WriteProcessMemory, just to be sure..maybe that will help?

-nt20

EAX
May 16th, 2004, 01:35
you can do that you are doing, but is an easy way to do it, and not only is aplied to one process.
here is a code sample, is in asm.
but only works on win98/me, because xp and nt do not admit the VirtualProtectEx on a shared memory page.

EAX
May 16th, 2004, 01:48
fist of all :Sorry my english.
Hey you, why did you think that every section have a protection flags: RWX and some others like share, etc.
This is because every process have a 4gb of virtual memory, this is not actually the real RAM memory but is emulated by a paging process.
The common page size is 4k = 4096 bytes, so every space addres of each proces is dividen in pages of 4k maximum, each page can be commited,free or reserved; and each one have protection flags for access.
you cant just go wherever you want and write, even there is places where you cant even read.
So you fist must do this,
1)determinate the address to write
2)call VirtualQueryEx specifing that address, this function retrieve the base address of the page that contains that address and his size (in the structure BASIC_MEMORY_INFORMATION), and also gives the protection mode.
3)If the page is read only, execute, execute read or some else you must have to change to execute_read_write. You can do this whit the function VirtualProtectEx
4)you change the value at the address
5)Set the previous page protection.

So that is all, an one more recomendation, change to asm32 and make me a happy
_______________EAX

EAX
May 16th, 2004, 01:58
Here is a help that isnt so much if you dont know assember, if you dont know asm you must start to do it because you lose a lot of resources in programming if you only know only one language, even more if you that isnt assembler because you can do EVERYTING with asm.
have luck with your proggie, i hoppe this info to be usefull to you.

here is an local api hook of the MessageBoxA
________EAX