Log in

View Full Version : Altering an Imported Function


RobertReed
February 20th, 2009, 20:34
Problem: I need to rewrite a function that is being imported by my program.

Specifically: There are about 550 calls to _time64() in my program. I would like to re-assemble the imported function (_time64) so that it returns specific values required by my current project.

(Note: I do not want to patch the DLL it is being imported from because other programs require correct values from _time64().)

Strategy:
1. Assemble my own function and patch it somewhere into the application or into a new DLL.
2. Alter the import table so that _time64() points to my new function.

Does anyone know of any tutorials that demonstrate how to alter the import table in such a way? Otherwise, any suggestions or advice would be appreciated.

Thanks.

r3aper
February 20th, 2009, 22:02
I haven't searched for any tutorials and I've never done that myself, but I think what you're looking for is called API Hooking, give it a try.
I've read a while back, that microsoft has a project called Detours that makes it easy to implement an API hook.

Hope it helps.

r3aper

RobertReed
February 21st, 2009, 01:52
Thanks for the tip. I'll definitely study API Hooking.

Right now I'm looking into "code injection", specifically using MHS. Will post my results as I progress.

arc_
February 21st, 2009, 07:30
Calling imported functions usually happens as follows:
Code:
on every location in the program that needs time64:
call _time64
_time64: (one occurence)
jmp dword ptr [__imp_time64]
__imp_time64: (one occurence)
dd absolute_address_of_time64


There are plenty of ways to redirect this. You could add code that, on program startup, installs a hook in the time64 function (place a jmp to your replacement code). You could add a new import table entry (importing a function from your .dll) and change the _time64 jmp to use that. But the easiest option is probably to place your replacement code somewhere in the .exe, and replace the jmp dword ptr [] by a regular jump to it. That way you don't even need to touch the import table.

RobertReed
February 24th, 2009, 17:30
arc, I actually implemented your last suggestion.

What I initially did was this:

1. Found an insignificant portion of my program, NOPed out the code, and replaced it with my replacement function for _time64().

2. Search-and-replaced the byte codes for call _time64() with the byte codes to my replacement function.

Step 2 turned out to be a colossal failure. I didn't realise that the byte codes for a call within an executable change depending on where they are called within the executable! That is, the byte codes are relative to the calling location. (Byte codes for imported functions, like _time64(), seem to be absolute -- which makes sense.)

So, my replacement _time64() procedure location was patched at virtual address 40D5E6. In HIEW, I kept trying to assemble the instruction:

call 40D5E6

But it kept returning an address other than 40D5E6. After I realised my error, I assembled with the following syntax:

call .40D5E6

When you place the dot in front of your virtual address, HIEW figures out exactly what byte code sequence will get you to that address. I ended up having to manually type that instruction at every _time64() call in the program -- 30 locations! A royal pain, but I knew no other way.

The program is now running as I wanted it.

This obviously is not the most efficient strategy to attack a problem like this. When faced with a larger problem size, say 500+ calls to _time64(), it wouldn't scale. In this case, as suggested above by arc_, hooking the function and redirecting to our code would have been more scaleable.

I'm going to create a crackme project that will demonstrate some of problems hooking solves and how powerful a method it is in any RCEs skillset. Hopefully some of our more knowledgeable members can shed some light on how it's done. Will post soon...

RobertReed
February 24th, 2009, 20:16
Quote:
[Originally Posted by arc_;79454]Calling imported functions usually happens as follows:
Code:
on every location in the program that needs time64:
call _time64
_time64: (one occurence)
jmp dword ptr [__imp_time64]
__imp_time64: (one occurence)
dd absolute_address_of_time64


On the program I'm working on, it called the import address directly:

call ds:_time64

No redirection or JMPs. Would you go about it as stated in your reply:

1. Add a new IAT entry for dummy.dll, which exports dummy_proc ()

2. ...I'm not sure what next because _time64 is being called with its absolute address (call ds:_time64); and _time64 is tied to msvcr90.dll in its IAT entry.

I guess you would search-replace the byte codes of call ds:_time64 with the byte codes of call ds:dummy. Straight search-and-replace would work because the byte codes are absolute -- never change, regardless of location -- for inter-module calls, unlike intra-module which require a location context to figure out the byte codes.

arc_
February 25th, 2009, 07:42
Yes, regular calls (and jumps) are indeed encoded with an offset relative to the instruction's position, rather than the absolute address. It must've been painful to find that out the way you did, but at least you will never forget it now .

Quote:
[Originally Posted by RobertReed;79486]On the program I'm working on, it called the import address directly:

call ds:_time64


Interesting . You don't see that often.

Writing a .dll and adding a new import for it in your target, then redirecting every call is one way in which you could solve this. I'd be cautious though about the redirection and rather not do a straight search-and-replace; who knows, maybe you'll end up replacing a byte sequence that contains the same address but has actually nothing to do with it (not very likely, granted, but possible). It would be better to disassemble the program with IDA and write a script to output all references to the _time64 dword to a file, then write a small patcher program that reads this list and patches the target accordingly. (It may even be possible to do the patching straight from IDA, not sure - maybe someone else can jump in here)

Another, less work intensive, possibility is the following: change the entry point of the program to an empty area, and add code there that overwrites the _time64 import dword with the absolute address of your (in-program) replacement code (ie runtime patching), then jumps to the real entry point. All call dword [_time64]'s will still read their dword from the same address, but the address stored there has now changed.

Note that for the second approach to work, you will probably need to change the import section's characteristics to make it writable. This, and changing the entry point, can be done easily with a tool like PEditor.

Externalist
February 25th, 2009, 10:48
A small utility used for unpacking called "Universal Import Fixer" can automatically fix all direct imports to a call [function in IAT] type. It creates a new IAT in heap space and combines all the 'direct imports' and 'non direct imports' into one nicely formatted IAT. That combined with Import Reconstructor might probably help you resolve your problem.

Greyhound2004
February 28th, 2009, 05:20
Please forgive me if this is rubbish but i'm interested in this as a possible approach to 'cracking' a program.
I'm thinking in this case of a VB prog where the compare function is within one of the imports.
would it be possible to copy the dll and edit it in such a way that negates the compare function. Then point the program to this new modified dll ?
Regards.

Darren
February 28th, 2009, 10:19
http://www.nirsoft.net/utils/run_as_date.html

Might help you

Darren