Настало время наполнить нашу DLL кодом!
Для начала преобразуем проект Visual Studio под DLL, для этого изменим Makefile:
Заметьте, появились новые флаги:
/DLL – говорит link.exe собирать динамическую библиотеку
/DEF:Version.def – в файле размещаются функции, которые будет экспортировать наша библиотека
Файл Version.def пока не имеет функций, это лишь только заготовка:
main.c
Нажимаем в F7 и наша DLL скомпилирована.
Начинаем новые эксперименты, подкидываем полученную Version.dll к распакованному TeamViewer (в папку tvfiles) и запускаем TeamViewer.exe.
Получаем ошибку при загрузке Version.dll
Эти ошибки означают то что загрузчик не смог найти в экспорте Version.dll нужных функций. Удовлетворим потребность Windows загрузчика! Для этого:
На вход функции GetAPI подается два параметра lib – имя библиотеки, name – имя функции. LoadLibraryA загружает динамическую библиотеку по абсолютному пути, тем самым мы избегаемhijacking.
Рассмотрим этот процесс по шагам:
В DllMain я добавил вывод сообщения – MessageBoxA(0,”I’m Hacker! ufolabs.pro”,”Hi”,0), которое будет отображаться при успешной загрузке Version.dll
Version.def
Makefile
Компилируем и убеждаемся что у Version.dll появился экспорт. Для этого переходим в Far к Version.dll и нажимаем Alt+F4 -> Enter (hex отображение) -> F8 -> F9 (просмотр экспорта) И увидим в Hiew:
Забрасываем Version.dll в tvfiles, запускаем TeamViewer.exe и видим сообщение:
После нажатия OKей, ошибок c экспортом больше нет, TeamViewer запустился. Это означает что мы подменили функции корректно.
Настраиваем отладку
Для удобной разработки кода в Version.dll нужно настроить отладку в Visual Studio, для этого размещаем распакованный tvfiles рядом с каталогом проекта tv, и в настройках студии прописываем путь до файла TeamViewer.exe
При запуске студия скажет, что не нашла символы pdb, и спросит нужно ли исполнять файл, выбираем Yes, и можно поставить галочку что бы окно больше не появлялось.
Теперь мы можем отлаживать код внутри процесса TeamViewer.exe, не правда ли удобно?
Для начала преобразуем проект Visual Studio под DLL, для этого изменим Makefile:
Код:
CFLAGS=/c /GS- /MT
LDFLAGS=/DLL /SUBSYSTEM:WINDOWS,"5.1"
NAME=
INCPATH=/I.
LIBPATH=
SRC=main.c
OBJ=main.obj
LIBS=
NAME=Version.dll
all:
cl.exe $(CFLAGS) $(SRC) $(INCPATH)
link.exe $(LDFLAGS) $(LIBS) $(OBJ) /DEF:Version.def $(LIBPATH) /OUT:Version.dll
bdebug:
cl.exe $(CFLAGS) /Zi $(SRC) $(INCPATH)
link.exe $(LDFLAGS) $(LIBS) $(OBJ) /DEF:Version.def $(LIBPATH) /DEBUG /OUT:Version.dll
/DLL – говорит link.exe собирать динамическую библиотеку
/DEF:Version.def – в файле размещаются функции, которые будет экспортировать наша библиотека
Файл Version.def пока не имеет функций, это лишь только заготовка:
Код:
LIBRARY Version.dll
Код:
#include <Windows.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
BOOL WINAPI DllMain(
HINSTANCE hinstDLL, // handle to DLL module
DWORD fdwReason, // reason for calling function
LPVOID lpReserved ) // reserved
{
// Perform actions based on the reason for calling.
switch( fdwReason )
{
case DLL_PROCESS_ATTACH:
break;
case DLL_THREAD_ATTACH:
// Do thread-specific initialization.
break;
case DLL_THREAD_DETACH:
// Do thread-specific cleanup.
break;
case DLL_PROCESS_DETACH:
// Perform any necessary cleanup.
break;
}
return TRUE; // Successful DLL_PROCESS_ATTACH.
}
Начинаем новые эксперименты, подкидываем полученную Version.dll к распакованному TeamViewer (в папку tvfiles) и запускаем TeamViewer.exe.
Получаем ошибку при загрузке Version.dll

Эти ошибки означают то что загрузчик не смог найти в экспорте Version.dll нужных функций. Удовлетворим потребность Windows загрузчика! Для этого:
- Объявляем функцию с таким же названием как в ошибке
- В теле функции получаем адрес оригинальной и вызываем её
Код:
VOID *GetAPI(char *lib,char *name)
{
HMODULE mod;
CHAR path[MAX_PATH];
CHAR fname[MAX_PATH];
GetSystemDirectoryA(path,MAX_PATH);
sprintf(fname,"%s\\%s",path,lib);
mod=LoadLibraryA(fname);
if (mod)
{
return GetProcAddress(mod,name);
}
return 0;
}
Рассмотрим этот процесс по шагам:
- Запоминаем название функции из сообщения об ошибке (например, GetFileVersionInfoSizeW)
- Гуглим “GetFileVersionInfoSizeW msdn”
- Смотрим в каком заголовочном файле (header) объявлена наша функция – Windows.h
- Вписываем слово GetFileVersionInfoSizeW в DllMain и нажимаем F12 (Go To Definition), тем самым переходя на ее объявление.
Код:DWORD APIENTRY GetFileVersionInfoSizeW( __in LPCWSTR lptstrFilename, /* Filename of version stamped file */ __out_opt LPDWORD lpdwHandle /* Information for use by GetFileVersionInfo */ );
- Копируем объявление функции и вставляем в main.c
Код:DWORD (APIENTRY *fGetFileVersionInfoSizeW)( __in LPCWSTR lptstrFilename, /* Filename of version stamped file */ __out_opt LPDWORD lpdwHandle /* Information for use by GetFileVersionInfo */ ); DWORD APIENTRY GetFileVersionInfoSizeW( __in LPCWSTR lptstrFilename, /* Filename of version stamped file */ __out_opt LPDWORD lpdwHandle /* Information for use by GetFileVersionInfo */ ) { fGetFileVersionInfoSizeW=GetAPI("VERSION.dll","GetFileVersionInfoSizeW"); if (!fGetFileVersionInfoSizeW) { return 0; } return fGetFileVersionInfoSizeW(lptstrFilename,lpdwHandle); }
- Добавляем имя функции GetFileVersionInfoSizeW в Version.def
Код:LIBRARY Version.dll EXPORTS GetFileVersionInfoSizeW
- Компилируем по F7, и убеждаемся что нет ошибок.
- Повторяем до получения рабочей библиотеки =)
Код:
#include <Windows.h>
#include <Winternl.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
VOID *GetAPI(char *lib,char *name)
{
HMODULE mod;
CHAR path[MAX_PATH];
CHAR fname[MAX_PATH];
GetSystemDirectoryA(path,MAX_PATH);
sprintf(fname,"%s\\%s",path,lib);
mod=LoadLibraryA(fname);
if (mod)
{
return GetProcAddress(mod,name);
}
return 0;
}
DWORD
(APIENTRY
*fGetFileVersionInfoSizeW)(
__in LPCWSTR lptstrFilename, /* Filename of version stamped file */
__out_opt LPDWORD lpdwHandle /* Information for use by GetFileVersionInfo */
);
DWORD
APIENTRY
GetFileVersionInfoSizeW(
__in LPCWSTR lptstrFilename, /* Filename of version stamped file */
__out_opt LPDWORD lpdwHandle /* Information for use by GetFileVersionInfo */
)
{
fGetFileVersionInfoSizeW=GetAPI("VERSION.dll","GetFileVersionInfoSizeW");
if (!fGetFileVersionInfoSizeW)
{
return 0;
}
return fGetFileVersionInfoSizeW(lptstrFilename,lpdwHandle);
}
BOOL
(APIENTRY
*fGetFileVersionInfoW)(
__in LPCWSTR lptstrFilename, /* Filename of version stamped file */
__reserved DWORD dwHandle, /* Information from GetFileVersionSize */
__in DWORD dwLen, /* Length of buffer for info */
__out_bcount(dwLen) LPVOID lpData /* Buffer to place the data structure */
);
BOOL
APIENTRY
GetFileVersionInfoW(
__in LPCWSTR lptstrFilename, /* Filename of version stamped file */
__reserved DWORD dwHandle, /* Information from GetFileVersionSize */
__in DWORD dwLen, /* Length of buffer for info */
__out_bcount(dwLen) LPVOID lpData /* Buffer to place the data structure */
)
{
fGetFileVersionInfoW=GetAPI("VERSION.dll","GetFileVersionInfoW");
if (!fGetFileVersionInfoW)
{
return 0;
}
return fGetFileVersionInfoW(lptstrFilename,dwHandle,dwLen,lpData);
}
BOOL
(APIENTRY
*fVerQueryValueW)(
__in LPCVOID pBlock,
__in LPCWSTR lpSubBlock,
__deref_out_xcount("buffer can be PWSTR or DWORD*") LPVOID * lplpBuffer,
__out PUINT puLen
);
BOOL
APIENTRY
VerQueryValueW(
__in LPCVOID pBlock,
__in LPCWSTR lpSubBlock,
__deref_out_xcount("buffer can be PWSTR or DWORD*") LPVOID * lplpBuffer,
__out PUINT puLen
)
{
fVerQueryValueW=GetAPI("VERSION.dll","VerQueryValueW");
if (!fVerQueryValueW)
{
return 0;
}
return fVerQueryValueW(pBlock,lpSubBlock,lplpBuffer,puLen);
}
BOOL
(APIENTRY
*fGetFileVersionInfoA)(
__in LPCSTR lptstrFilename, /* Filename of version stamped file */
__reserved DWORD dwHandle, /* Information from GetFileVersionSize */
__in DWORD dwLen, /* Length of buffer for info */
__out_bcount(dwLen) LPVOID lpData /* Buffer to place the data structure */
);
BOOL
APIENTRY
GetFileVersionInfoA(
__in LPCSTR lptstrFilename, /* Filename of version stamped file */
__reserved DWORD dwHandle, /* Information from GetFileVersionSize */
__in DWORD dwLen, /* Length of buffer for info */
__out_bcount(dwLen) LPVOID lpData /* Buffer to place the data structure */
)
{
fGetFileVersionInfoA=GetAPI("VERSION.dll","GetFileVersionInfoA");
if (!fGetFileVersionInfoA)
{
return 0;
}
return fGetFileVersionInfoA(lptstrFilename,dwHandle,dwLen,lpData);
}
BOOL (APIENTRY *fGetFileVersionInfoExW)(__in DWORD dwFlags,
__in LPCWSTR lpwstrFilename,
__reserved DWORD dwHandle,
__in DWORD dwLen,
__out_bcount(dwLen) LPVOID lpData);
BOOL APIENTRY GetFileVersionInfoExW(__in DWORD dwFlags,
__in LPCWSTR lpwstrFilename,
__reserved DWORD dwHandle,
__in DWORD dwLen,
__out_bcount(dwLen) LPVOID lpData)
{
fGetFileVersionInfoExW=GetAPI("VERSION.dll","GetFileVersionInfoExW");
if (!fGetFileVersionInfoExW)
{
return 0;
}
return fGetFileVersionInfoExW(dwFlags,lpwstrFilename,dwHandle,dwLen,lpData);
}
DWORD (APIENTRY *fGetFileVersionInfoSizeExA)(__in DWORD dwFlags, __in LPCSTR lpwstrFilename, __out LPDWORD lpdwHandle);
DWORD APIENTRY GetFileVersionInfoSizeExA(__in DWORD dwFlags, __in LPCSTR lpwstrFilename, __out LPDWORD lpdwHandle)
{
fGetFileVersionInfoSizeExA=GetAPI("VERSION.dll","GetFileVersionInfoSizeExA");
if (!fGetFileVersionInfoSizeExA)
{
return 0;
}
return fGetFileVersionInfoSizeExA(dwFlags,lpwstrFilename,lpdwHandle);
}
DWORD (APIENTRY *fGetFileVersionInfoSizeExW)(__in DWORD dwFlags, __in LPCWSTR lpwstrFilename, __out LPDWORD lpdwHandle);
DWORD APIENTRY GetFileVersionInfoSizeExW(__in DWORD dwFlags, __in LPCWSTR lpwstrFilename, __out LPDWORD lpdwHandle)
{
fGetFileVersionInfoSizeExW=GetAPI("VERSION.dll","GetFileVersionInfoSizeExW");
if (!fGetFileVersionInfoSizeExW)
{
return 0;
}
return fGetFileVersionInfoSizeExW(dwFlags,lpwstrFilename,lpdwHandle);
}
DWORD
(APIENTRY
*fGetFileVersionInfoSizeA)(
__in LPCSTR lptstrFilename, /* Filename of version stamped file */
__out_opt LPDWORD lpdwHandle /* Information for use by GetFileVersionInfo */
);
DWORD
APIENTRY
GetFileVersionInfoSizeA(
__in LPCSTR lptstrFilename, /* Filename of version stamped file */
__out_opt LPDWORD lpdwHandle /* Information for use by GetFileVersionInfo */
)
{
fGetFileVersionInfoSizeA=GetAPI("VERSION.dll","GetFileVersionInfoSizeA");
if (!fGetFileVersionInfoSizeA)
{
return 0;
}
return fGetFileVersionInfoSizeA(lptstrFilename,lpdwHandle);
}
BOOL
(APIENTRY
*fVerQueryValueA)(
__in LPCVOID pBlock,
__in LPCSTR lpSubBlock,
__deref_out_xcount("buffer can be PWSTR or DWORD*") LPVOID * lplpBuffer,
__out PUINT puLen
);
BOOL
APIENTRY
VerQueryValueA(
__in LPCVOID pBlock,
__in LPCSTR lpSubBlock,
__deref_out_xcount("buffer can be PWSTR or DWORD*") LPVOID * lplpBuffer,
__out PUINT puLen
)
{
fVerQueryValueA=GetAPI("VERSION.dll","VerQueryValueA");
if (!fVerQueryValueA)
{
return 0;
}
return fVerQueryValueA(pBlock,lpSubBlock,lplpBuffer,puLen);
}
BOOL WINAPI DllMain(
HINSTANCE hinstDLL, // handle to DLL module
DWORD fdwReason, // reason for calling function
LPVOID lpReserved ) // reserved
{
// Perform actions based on the reason for calling.
switch( fdwReason )
{
case DLL_PROCESS_ATTACH:
MessageBoxA(0,"I'm Hacker!","Hi",0);
break;
case DLL_THREAD_ATTACH:
// Do thread-specific initialization.
break;
case DLL_THREAD_DETACH:
// Do thread-specific cleanup.
break;
case DLL_PROCESS_DETACH:
// Perform any necessary cleanup.
break;
}
return TRUE; // Successful DLL_PROCESS_ATTACH.
}
Version.def
Код:
LIBRARY Version.dll
EXPORTS
GetFileVersionInfoSizeW
GetFileVersionInfoW
VerQueryValueW
VerQueryValueA
GetFileVersionInfoExW
GetFileVersionInfoA
GetFileVersionInfoSizeA
GetFileVersionInfoSizeExW
GetFileVersionInfoSizeExA
Makefile
Код:
CFLAGS=/c /GS- /MT
LDFLAGS=/DLL /SUBSYSTEM:WINDOWS,"5.1"
NAME=
INCPATH=/I.
LIBPATH=
SRC=main.c
OBJ=main.obj
LIBS=user32.lib
NAME=Version.dll
all:
cl.exe $(CFLAGS) $(SRC) $(INCPATH)
link.exe $(LDFLAGS) $(LIBS) $(OBJ) /DEF:Version.def $(LIBPATH) /OUT:Version.dll
copy Version.dll ..\..\tvfiles\Version.dll
bdebug:
cl.exe $(CFLAGS) /Zi $(SRC) $(INCPATH)
link.exe $(LDFLAGS) $(LIBS) $(OBJ) /DEF:Version.def $(LIBPATH) /DEBUG /OUT:Version.dll
copy Version.dll ..\..\tvfiles\Version.dll

Забрасываем Version.dll в tvfiles, запускаем TeamViewer.exe и видим сообщение:

После нажатия OKей, ошибок c экспортом больше нет, TeamViewer запустился. Это означает что мы подменили функции корректно.
Настраиваем отладку
Для удобной разработки кода в Version.dll нужно настроить отладку в Visual Studio, для этого размещаем распакованный tvfiles рядом с каталогом проекта tv, и в настройках студии прописываем путь до файла TeamViewer.exe

При запуске студия скажет, что не нашла символы pdb, и спросит нужно ли исполнять файл, выбираем Yes, и можно поставить галочку что бы окно больше не появлялось.
Теперь мы можем отлаживать код внутри процесса TeamViewer.exe, не правда ли удобно?
