Jump to content
Tuts 4 You

Detours Problem Linking


mjones

Recommended Posts

i'm having trouble linking a simple dll to do function detouring in windows. everything is pretty straightforward but i haven't been able to resolve these linking errors:

test.obj : error LNK2005: "void * (__stdcall* pCreateFileW)(wchar_t const *,unsigned long,unsigned long,struct _SECURITY_ATTRIBUTES *,unsigned long,unsigned long,void *)" (?pCreateFileW@@3P6GPAXPB_WKKPAU_SECURITY_ATTRIBUTES@@KKPAX@ZA) already defined in main.obj
Z:\test\Debug\test.dll : fatal error LNK1169: one or more multiply defined symbols found

here is what i've done thus far.

1. installing detours

- downloaded detours express 3.0 from http://research.micr...ojects/detours/

- added VC10\bin to %PATH%

- ran vcvars32.bat

- ran nmake under detours src and samples directories

- copied contents of detours include and lib.X86 directories to VC include and lib directories, respectively

all of that went off without a hitch, as they say.

2. started a new project in vc++ 2010, type dll, empty application. i have three files:

test.h:

// test.h
#ifndef _TELLME_H_
#define _TELLME_H_
#endif#include <Windows.h>HANDLE (WINAPI *pCreateFileW)(LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) = CreateFileW;
HANDLE WINAPI MyCreateFileW(LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile);

test.cpp:

// test.cpp
#include "test.h"HANDLE WINAPI MyCreateFileW(LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) {
OutputDebugString(lpFileName);
return pCreateFileW(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
}

main.cpp:

// main.cpp
#pragma comment(lib, "detours.lib")#include "test.h"
#include "detours.h"__declspec(dllexport) INT APIENTRY DllMain(HMODULE hDLL, DWORD Reason, LPVOID Reserved) {
switch(Reason) {
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hDLL);
DetourTransactionbegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)pCreateFileW, MyCreateFileW);
if(DetourTransactionCommit() == NO_ERROR)
OutputDebugString(L"\nCreateFileW() detoured successfully\n");
break;
case DLL_PROCESS_DETACH:
DetourTransactionbegin();
DetourUpdateThread(GetCurrentThread());
DetourDetach(&(PVOID&)pCreateFileW, MyCreateFileW);
if(DetourTransactionCommit() == NO_ERROR)
OutputDebugString(L"\nCreateFileW() detour detached successfully\n");
break;
}return TRUE;
}

when i build the project, i get the linker errors mentioned in the top of the post. i've been googling around but the results coming back just say to "find where the problem is" and i've got no idea what it is i should be looking for to figure out "where the problem is". i added /verbose:lib into the linker options and the output listed the libraries, but i can't tell which, if any, are problematic or if the ordering is the issue (and what the proper order should be) or what.

here is the output from the build, using /verbose:lib:


------ Build started: Project: test, Configuration: Debug Win32 ------
Build started 10/14/2012 1:23:19 PM.
InitializeBuildStatus:
Touching "Debug\test.unsuccessfulbuild".
ClCompile:
All outputs are up-to-date.
test.obj : error LNK2005: "void * (__stdcall* pCreateFileW)(wchar_t const *,unsigned long,unsigned long,struct _SECURITY_ATTRIBUTES *,unsigned long,unsigned long,void *)" (?pCreateFileW@@3P6GPAXPB_WKKPAU_SECURITY_ATTRIBUTES@@KKPAX@ZA) already defined in main.objSearching libraries
Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\kernel32.lib:
Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\user32.lib:
Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\gdi32.lib:
Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\winspool.lib:
Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\comdlg32.lib:
Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\advapi32.lib:
Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\shell32.lib:
Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\ole32.lib:
Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\oleaut32.lib:
Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\uuid.lib:
Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\odbc32.lib:
Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\odbccp32.lib:
Searching C:\xp\Development\Microsoft Visual Studio 10.0\VC\lib\detours.lib:
Searching C:\xp\Development\Microsoft Visual Studio 10.0\VC\lib\MSVCRTD.lib:
Searching C:\xp\Development\Microsoft Visual Studio 10.0\VC\lib\OLDNAMES.lib:
Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\kernel32.lib:
Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\user32.lib:
Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\gdi32.lib:
Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\winspool.lib:
Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\comdlg32.lib:
Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\advapi32.lib:
Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\shell32.lib:
Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\ole32.lib:
Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\oleaut32.lib:
Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\uuid.lib:
Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\odbc32.lib:
Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\odbccp32.lib:
Searching C:\xp\Development\Microsoft Visual Studio 10.0\VC\lib\detours.lib:Finished searching libraries
Creating library Z:\test\Debug\test.lib and object Z:\test\Debug\test.expSearching libraries
Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\kernel32.lib:
Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\user32.lib:
Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\gdi32.lib:
Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\winspool.lib:
Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\comdlg32.lib:
Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\advapi32.lib:
Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\shell32.lib:
Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\ole32.lib:
Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\oleaut32.lib:
Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\uuid.lib:
Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\odbc32.lib:
Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\odbccp32.lib:
Searching C:\xp\Development\Microsoft Visual Studio 10.0\VC\lib\detours.lib:
Searching C:\xp\Development\Microsoft Visual Studio 10.0\VC\lib\MSVCRTD.lib:
Searching C:\xp\Development\Microsoft Visual Studio 10.0\VC\lib\OLDNAMES.lib:Finished searching libraries
Z:\test\Debug\test.dll : fatal error LNK1169: one or more multiply defined symbols foundBuild FAILED.Time Elapsed 00:00:03
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Link to comment

Moving all code into one file and getting rid of test.h and test.cpp solves all the problems. Good enough for me. ;)

Hopefully some smarter person will be able to suggest proper solution.

Link to comment

all the examples i've seen have everything in one file. i want to end up detouring several dozen APIs though so would really like to separate things if possible.

Link to comment

You can achieve what you want using externs:

main.cpp:


#include <Windows.h>#pragma comment( lib, "detours.lib" )
#include <detours.h>
#include "CreateFileW.h"extern "C" HANDLE ( WINAPI *Real_CreateFileW )( LPCWSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE );BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD fdwReason, LPVOID lpvReserved )
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
{
DisableThreadLibraryCalls( hInstance );
DetourTransactionbegin();
DetourUpdateThread( GetCurrentThread() );
DetourAttach( &(PVOID&)Real_CreateFileW, Mine_CreateFileW );
DetourTransactionCommit();
break;
}
}
return TRUE;
}

CreateFileW.h:


#ifndef __CREATEFILEW_H_INCLUDED__
#define __CREATEFILEW_H_INCLUDED__#include <Windows.h>HANDLE WINAPI Mine_CreateFileW(
_In_ LPCWSTR lpFileName,
_In_ DWORD dwDesiredAccess,
_In_ DWORD dwShareMode,
_In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
_In_ DWORD dwCreationDisposition,
_In_ DWORD dwFlagsAndAttributes,
_In_opt_ HANDLE hTemplateFile
);#endif // __CREATEFILEW_H_INCLUDED__

CreateFileW.cpp:


#include "CreateFileW.h"extern "C"
{
HANDLE ( WINAPI *Real_CreateFileW )( LPCWSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE ) = CreateFileW;
}HANDLE WINAPI Mine_CreateFileW(
_In_ LPCWSTR lpFileName,
_In_ DWORD dwDesiredAccess,
_In_ DWORD dwShareMode,
_In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
_In_ DWORD dwCreationDisposition,
_In_ DWORD dwFlagsAndAttributes,
_In_opt_ HANDLE hTemplateFile
)
{
OutputDebugString( lpFileName );
return Real_CreateFileW( lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile );
}
Link to comment

You're providing two definitions for pCreateFileW. You defined the function pCreateFileW in test.h and then you included test.h in both test.cpp and main.cpp. Doing this causes the linker to get confused as it doesn't know which definition to use (even though they're the same). This would be the same as declaring two variables with the same name in one .cpp.

To resolve this issue do this:


//test.hextern HANDLE (WINAPI *pCreateFileW)(args...); //no = CreateFileW. You could (not 100% sure though) but it is not a good practice. When dealing with externs it is always the best to provide the declaration in a .h and the definition in a .cpp.
MyCreateFileW prototype...

//test.cpp#include "test.h"
MyCreateFileW definition...

//main.cpp#include <other stuff>
#include "test.h"pCreateFileW = CreateFileW;other stuff here...

What extern really does is it exposes your variable (which is defined in some .cpp) to any .cpp that includes the .h in which that variable was declared.

Hope this helps,

iLovro

Edited by iLovro
  • Like 2
Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...