5

Generally when I have Vista application it upgrade few function from kernel32.dll

most often being InitializeCriticalSection -> InitializeCriticalSectionEx

Is it possibly to backport such? beside changing linker OSVersion.

Edit: Just to be verbose, here is the example

.text:0048CE4D                 xor     esi, esi
.text:0048CE4F                 push    esi             ; Flags
.text:0048CE50                 push    esi             ; dwSpinCount
.text:0048CE51                 push    ecx             ; lpCriticalSection
.text:0048CE52                 call    ds:InitializeCriticalSectionEx
.text:0048CE58                 test    eax, eax

hex dump: 33 F6 56 56 51 FF 15 F0 C1 4A 00 85 C0

5

One way to do this is to create "shim" DLLs with similar names so that they are easy to recognize. This technique can be used incrementally (i.e. additional functions can be added to the DLL at any time, for other programs with similar requirements, rather than using an entirely new DLL each time).

The initial problem is that you can't simply replace the function names (i.e. CriticalSectionEx -> CriticalSection), because of the additional parameters that are required.

The shim technique requires that you change only the name of the imported DLL in the exe file, for example from "kernel32.dll" to "kernel31.dll" (to preserve the length of the name and maintain data alignment). Then you create a "kernel31.dll", which is placed in the same directory as the exe file. The contents of this "kernel31.dll" file will be an export table, an import table, and wrappers for some functions.

To create the import table, you need another program which will read the import table of your original exe, and perform a GetProcAddress on each entry. For each entry that returns a valid address, the "kernel31.dll" export table will have that entry added directly, and will point to the "kernel31.dll" import table in order to forward that imported name to the original DLL. This function has no compatibility issues.

For each entry that returns a zero for the address, the "kernel31.dll" export table will point to a wrapper inside "kernel31.dll" that you would have to write yourself.

Repeat this procedure for each of the DLLs in the original exe (so "ntdll.dll" could become "ntdl1.dll", "user32.dll" could become "user31.dll", etc).

There are two special cases, though: LoadLibrary and its variants (and its equivalent in ntdll.dll), and GetModuleHandle and its variants (and its equivalent in ntdll.dll). These require wrappers in the "kernel31.dll" because they might attempt to access dynamically DLLs or functions which will have compatibility issues, too. Unfortunately, you can't really determine that through static analysis.

These two wrappers will call the original function in kernel32.dll (or ntdll.dll), and then check the result. If a DLL does not exist, then it's a case of creating that DLL yourself, in case it was introduced in a later version of Windows, or returning this result if the DLL is truly optional. If the function does not exist, then it's a case of finding the reference to the DLL and renaming it, and then writing the function wrapper for a new version of that DLL.

That's a horribly long answer, and probably makes it sound more difficult to implement that it really is, but the details are needed.

| improve this answer | |
  • just curious does that shims available on torrent? too bad XP have SFC otherwise there woulde be kernelEx for XP – Kohl Emmert Jan 1 '16 at 18:00
  • In msvcp140.dll redist (which still support XP) I can find all missing *Ex functions but in the name of __crt[function]Ex. Can I redirect it to these? – Kohl Emmert Jan 3 '16 at 18:03
  • Additionally all missing secureapi also available in the other dlls that come with msvcp140 (those UCRT). – Kohl Emmert Jan 3 '16 at 18:15
  • yes, these functions should work. – peter ferrie Jan 3 '16 at 20:53
1

Not a trivial fix, but you could patch the Import Table to replace InitializeCriticalSectionEx with InitializeCriticalSection (just replace the E character with a null-byte) and then patch all calls that were initially to InitializeCriticalSectionEx to instead only pass the lpCriticalSection argument and not the dwSpinCount and Flags arguments. You'll need to do some extra work if there are other calls to this function that don't rely on a static import.

There are even uglier solutions like hooking Windows's PE loader to dynamically redirect things, but I wouldn't recommend that route.

Perhaps someone else can think of a more simple solution...?

| improve this answer | |
  • I try it, but it crashed with memory allocation error. I changed 56 56 with 00 00 in the hex dump, beside changing the import table – Kohl Emmert Jan 1 '16 at 18:04
  • 1
    Changing 56 56 to 00 00 is not in line with the advice I gave above. – Jason Geffner Jan 1 '16 at 23:15
  • ah sorry you're right – Kohl Emmert Jan 3 '16 at 17:32
0

It is easy as pie.

                33 F6 56 56 51 FF 15 F0 C1 4A 00 85 C0
changed into -> 33 F6 90 90 51 FF 15 F0 C1 4A 00 85 C0
                      ^^ ^^

And change the String in Import table

49 6E 69 74 69 61 6C 69 7A 65 43 72 69 74 69 63 61 6C 53 65 63 74 69 6F 6E 45 78 00 // InitializeCriticalSectionEx
49 6E 69 74 69 61 6C 69 7A 65 43 72 69 74 69 63 61 6C 53 65 63 74 69 6F 6E 00 00 00  // InitializeCriticalSection 
                                                                           ^^ ^^
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.