Saturday, November 19, 2016

SHGetKnownFolderPath: why is it linked with two jumps?

I noticed a weird behaviour when trying to detour SHGetKnownFolderPath, and investigaed a bit. So I worte a tiny program, and then loaded it in IDA.
The program:

#include "stdafx.h"
#include "windows.h"
#include "FileAPI.h"
#include "Shlobj.h"


int main()
{
    HANDLE hFile = CreateFileA(NULL, 0, 0, NULL, 0, 0, NULL);
    SHGetKnownFolderPath(FOLDERID_LocalAppDataLow, 0, NULL, NULL);
    return 0;
}
Looking in IDA, I see for CreateFileA:
call    ds:__imp__CreateFileA@28 ; CreateFileA(x,x,x,x,x,x,x)
Which takes me to:
.idata:0041B000 ; HANDLE __stdcall CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
.idata:0041B000                 extrn __imp__CreateFileA@28:dword ; CODE XREF: _main+2Ep
.idata:0041B000                                         ; DATA XREF: _main+2Er ...
On the other hand, for SHGetKnownFolderPath I see:
call    j__SHGetKnownFolderPath@16 ; SHGetKnownFolderPath(x,x,x,x)
Which redirect to:
; __stdcall SHGetKnownFolderPath(x, x, x, x)
j__SHGetKnownFolderPath@16 proc near
jmp     _SHGetKnownFolderPath@16 ; SHGetKnownFolderPath(x,x,x,x)
j__SHGetKnownFolderPath@16 endp
Which redirect to:
; __stdcall SHGetKnownFolderPath(x, x, x, x)
_SHGetKnownFolderPath@16 proc near
jmp     ds:__imp__SHGetKnownFolderPath@16 ; SHGetKnownFolderPath(x,x,x,x)
_SHGetKnownFolderPath@16 endp
Which redirect to:
.idata:0041B09C ; __declspec(dllimport) __stdcall SHGetKnownFolderPath(x, x, x, x)
.idata:0041B09C                 extrn __imp__SHGetKnownFolderPath@16:dword
.idata:0041B09C                                         ; DATA XREF: SHGetKnownFolderPath(x,x,x,x)r
So SHGetKnownFolderPath have two more jumps then CreateFileA. I did nothing to the project to make it do it. so why?

Update:
Removing Incremental Linking removed j__SHGetKnownFolderPath@16, but left _SHGetKnownFolderPath@16.
From the VS /INCREMENTAL documentation:

  • May contain jump thunks to handle relocation of functions to new addresses

So we have half a solution, and another question: why does this setting effect only this DLL, and not other DLLs? (especially other system DLLs)

Update 2: Solved.
Found out that SHGetKnownFolderPath does not have a __declspec(dllimport) in the definition. Adding it made it be called identical to CreateFileA.
Without it, the compiler created a stub, the linker add a stub of its own for the incremental linking, and only then connected it to the DLL.