使用代码注入在远程进程中执行函数
Executing function in remote process using code injection
我正在使用高级代码注入代码在远程进程上启动 .dll。
您可以从这里找到它的工作原理/代码片段:
https://sourceforge.net/p/diagnostic/svn/HEAD/tree/src/RemoteInit.cpp
我注意到对于某些应用程序,此方法不起作用 - 它会导致主机应用程序崩溃。主要问题似乎是特殊类型的第 3 方软件,如 ConEmuHk64.dll
,它通过提供自己的挂钩函数来拦截 kernel32.dll GetProcAddress
- 之后我得到这样的函数指针:
*((FARPROC*) &info.pfuncGetProcAddress) = GetProcAddress(hKernel32, "GetProcAddress");
但我得到的是指向位于 ConEmuHk64.dll 中的函数的指针。
在我自己的进程中调用该函数是可以接受的,但是当尝试在远程进程中执行相同的操作时 - 它崩溃了,因为 ConEmuHk64.dll
在那里不一定可用。
我已经弄清楚如何通过手动进入 DOS/NE 其他 header 来 auto-probe 更正该函数的地址的机制 - 这是代码片段:
//
// We use GetProcAddress as a base function, with exception to when GetProcAddress itself is hooked by 3-rd party
// software and pointer to function returned to us is incorrect - then we try to locate function manually by
// ourselfes.
//
FARPROC GetProcAddress2( HMODULE hDll, char* funcName )
{
FARPROC p = GetProcAddress( hDll, funcName );
if( !p )
return NULL;
IMAGE_DOS_HEADER* pDosHeader = (IMAGE_DOS_HEADER *) hDll;
if ( pDosHeader->e_magic != IMAGE_DOS_SIGNATURE )
return p;
IMAGE_NT_HEADERS* pNtHeaders = (IMAGE_NT_HEADERS *) (((char*) pDosHeader) + pDosHeader->e_lfanew);
if ( pNtHeaders->Signature != IMAGE_NT_SIGNATURE )
return p;
IMAGE_OPTIONAL_HEADER* pOptionalHeader = &pNtHeaders->OptionalHeader;
if( (char*) p >= (char*)hDll && (char*) p <= ((char*)hDll) + pOptionalHeader->SizeOfCode )
// Sounds like valid address.
return p;
// Does not sounds right, may be someone hooked given function ? (ConEmuHk64.dll or ConEmuHk.dll)
IMAGE_DATA_DIRECTORY* pDataDirectory = &pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
IMAGE_EXPORT_DIRECTORY* pExp = (IMAGE_EXPORT_DIRECTORY *) ((size_t) pDosHeader + pDataDirectory->VirtualAddress);
ULONG* addrofnames = (ULONG *) ((BYTE*) hDll + pExp->AddressOfNames);
ULONG* funcaddr = (ULONG*) ((BYTE*) hDll + pExp->AddressOfFunctions);
for ( DWORD i = 0; i < pExp->NumberOfNames; i++ )
{
char* funcname = (char*) ((BYTE*) hDll + addrofnames[i]);
if ( strcmp( funcname, funcName ) == 0 )
{
void* p2 = (void*) ((BYTE*) hDll + funcaddr[i]);
return (FARPROC) p2;
}
} //for
return p;
} //GetProcAddress2
这似乎适用于 GetProcAddress
- 我可以检测挂钩函数并覆盖它的行为。但是 - 这种方法并不通用。我已经尝试过对其他方法进行类似的函数调用,例如 FreeLibrary/AddDllDirectory/RemoveDllDirectory
- 并且那些函数指针精确指向 dll 边界之外 - GetProcAddress
returns DOS header.[= 之前的地址20=]
我怀疑通过 dll / 代码大小范围进行比较是不正确的:
if( (char*) p >= (char*)hDll && (char*) p <= ((char*)hDll) + pOptionalHeader->SizeOfCode )
但是不知道如何改进公式。
你能推荐我如何完全修复这个问题吗?这样任何第 3 方软件都可以拦截任何功能,并且我可以从中幸存下来而不会崩溃?
如果使用 "Exported function forward",则函数指针解析不正确(可以通过该术语进行搜索)。
一个合适的函数解析可以这样写:(你上面看到的是一些从某个论坛复制粘贴的函数)。
//
// We use GetProcAddress as a base function, with exception to when GetProcAddress itself is hooked by 3-rd party
// software and pointer to function returned to us is incorrect - then we try to locate function manually by
// ourselfes.
//
FARPROC GetProcAddress2( HMODULE hDll, char* funcName )
{
FARPROC p = GetProcAddress( hDll, funcName );
if( !p )
return NULL;
IMAGE_DOS_HEADER* pDosHeader = (IMAGE_DOS_HEADER *) hDll;
if ( pDosHeader->e_magic != IMAGE_DOS_SIGNATURE )
return p;
IMAGE_NT_HEADERS* pNtHeaders = (IMAGE_NT_HEADERS *) (((char*) pDosHeader) + pDosHeader->e_lfanew);
if ( pNtHeaders->Signature != IMAGE_NT_SIGNATURE )
return p;
IMAGE_OPTIONAL_HEADER* pOptionalHeader = &pNtHeaders->OptionalHeader;
if( (char*) p >= (char*)hDll && (char*) p <= ((char*)hDll) + pOptionalHeader->SizeOfCode )
// Sounds like valid address.
return p;
// Does not sounds right, may be someone hooked given function ? (ConEmuHk64.dll or ConEmuHk.dll)
IMAGE_DATA_DIRECTORY* pDataDirectory = &pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
IMAGE_EXPORT_DIRECTORY* pExp = (IMAGE_EXPORT_DIRECTORY *) ((size_t) pDosHeader + pDataDirectory->VirtualAddress);
ULONG* addrofnames = (ULONG *) ((BYTE*) hDll + pExp->AddressOfNames);
ULONG* funcaddr = (ULONG*) ((BYTE*) hDll + pExp->AddressOfFunctions);
for ( DWORD i = 0; i < pExp->NumberOfNames; i++ )
{
char* funcname = (char*) ((BYTE*) hDll + addrofnames[i]);
if ( strcmp( funcname, funcName ) == 0 )
{
ULONG addressOfFunction = funcaddr[i];
void* p2 = (void*) ((BYTE*) hDll + addressOfFunction);
if( addressOfFunction >= pDataDirectory->VirtualAddress && addressOfFunction < pDataDirectory->VirtualAddress + pDataDirectory->Size )
{
// "Exported function forward" - address of function can be found in another module.
// Actually for example AddDllDirectory is truly located in KernelBase.dll (alias api-ms-win-core-libraryloader-l1-1-0.dll ?)
char* dll_func = (char*) p2;
char* pdot = strchr(dll_func, '.');
if( !pdot ) pdot = dll_func + strlen( dll_func );
CStringA dllName(dll_func, (int)(pdot - dll_func));
dllName += ".dll";
HMODULE hDll2 = GetModuleHandleA(dllName);
if( hDll2 == NULL )
return p;
return GetProcAddress2( hDll2, pdot + 1 );
}
return (FARPROC) p2;
}
} //for
return p;
} //GetProcAddress2
除此之外,仍有可能将 .dll 加载到不同的地址,但这不会发生在 kernel32.dll 或 kernelbase.dll。
但是如果 .dll 变基成为问题 - 一种解决方法是使用 EasyHook 方法 - 可以在此处找到:
参见函数 GetRemoteFuncAddress。
我正在使用高级代码注入代码在远程进程上启动 .dll。 您可以从这里找到它的工作原理/代码片段:
https://sourceforge.net/p/diagnostic/svn/HEAD/tree/src/RemoteInit.cpp
我注意到对于某些应用程序,此方法不起作用 - 它会导致主机应用程序崩溃。主要问题似乎是特殊类型的第 3 方软件,如 ConEmuHk64.dll
,它通过提供自己的挂钩函数来拦截 kernel32.dll GetProcAddress
- 之后我得到这样的函数指针:
*((FARPROC*) &info.pfuncGetProcAddress) = GetProcAddress(hKernel32, "GetProcAddress");
但我得到的是指向位于 ConEmuHk64.dll 中的函数的指针。
在我自己的进程中调用该函数是可以接受的,但是当尝试在远程进程中执行相同的操作时 - 它崩溃了,因为 ConEmuHk64.dll
在那里不一定可用。
我已经弄清楚如何通过手动进入 DOS/NE 其他 header 来 auto-probe 更正该函数的地址的机制 - 这是代码片段:
//
// We use GetProcAddress as a base function, with exception to when GetProcAddress itself is hooked by 3-rd party
// software and pointer to function returned to us is incorrect - then we try to locate function manually by
// ourselfes.
//
FARPROC GetProcAddress2( HMODULE hDll, char* funcName )
{
FARPROC p = GetProcAddress( hDll, funcName );
if( !p )
return NULL;
IMAGE_DOS_HEADER* pDosHeader = (IMAGE_DOS_HEADER *) hDll;
if ( pDosHeader->e_magic != IMAGE_DOS_SIGNATURE )
return p;
IMAGE_NT_HEADERS* pNtHeaders = (IMAGE_NT_HEADERS *) (((char*) pDosHeader) + pDosHeader->e_lfanew);
if ( pNtHeaders->Signature != IMAGE_NT_SIGNATURE )
return p;
IMAGE_OPTIONAL_HEADER* pOptionalHeader = &pNtHeaders->OptionalHeader;
if( (char*) p >= (char*)hDll && (char*) p <= ((char*)hDll) + pOptionalHeader->SizeOfCode )
// Sounds like valid address.
return p;
// Does not sounds right, may be someone hooked given function ? (ConEmuHk64.dll or ConEmuHk.dll)
IMAGE_DATA_DIRECTORY* pDataDirectory = &pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
IMAGE_EXPORT_DIRECTORY* pExp = (IMAGE_EXPORT_DIRECTORY *) ((size_t) pDosHeader + pDataDirectory->VirtualAddress);
ULONG* addrofnames = (ULONG *) ((BYTE*) hDll + pExp->AddressOfNames);
ULONG* funcaddr = (ULONG*) ((BYTE*) hDll + pExp->AddressOfFunctions);
for ( DWORD i = 0; i < pExp->NumberOfNames; i++ )
{
char* funcname = (char*) ((BYTE*) hDll + addrofnames[i]);
if ( strcmp( funcname, funcName ) == 0 )
{
void* p2 = (void*) ((BYTE*) hDll + funcaddr[i]);
return (FARPROC) p2;
}
} //for
return p;
} //GetProcAddress2
这似乎适用于 GetProcAddress
- 我可以检测挂钩函数并覆盖它的行为。但是 - 这种方法并不通用。我已经尝试过对其他方法进行类似的函数调用,例如 FreeLibrary/AddDllDirectory/RemoveDllDirectory
- 并且那些函数指针精确指向 dll 边界之外 - GetProcAddress
returns DOS header.[= 之前的地址20=]
我怀疑通过 dll / 代码大小范围进行比较是不正确的:
if( (char*) p >= (char*)hDll && (char*) p <= ((char*)hDll) + pOptionalHeader->SizeOfCode )
但是不知道如何改进公式。
你能推荐我如何完全修复这个问题吗?这样任何第 3 方软件都可以拦截任何功能,并且我可以从中幸存下来而不会崩溃?
如果使用 "Exported function forward",则函数指针解析不正确(可以通过该术语进行搜索)。
一个合适的函数解析可以这样写:(你上面看到的是一些从某个论坛复制粘贴的函数)。
//
// We use GetProcAddress as a base function, with exception to when GetProcAddress itself is hooked by 3-rd party
// software and pointer to function returned to us is incorrect - then we try to locate function manually by
// ourselfes.
//
FARPROC GetProcAddress2( HMODULE hDll, char* funcName )
{
FARPROC p = GetProcAddress( hDll, funcName );
if( !p )
return NULL;
IMAGE_DOS_HEADER* pDosHeader = (IMAGE_DOS_HEADER *) hDll;
if ( pDosHeader->e_magic != IMAGE_DOS_SIGNATURE )
return p;
IMAGE_NT_HEADERS* pNtHeaders = (IMAGE_NT_HEADERS *) (((char*) pDosHeader) + pDosHeader->e_lfanew);
if ( pNtHeaders->Signature != IMAGE_NT_SIGNATURE )
return p;
IMAGE_OPTIONAL_HEADER* pOptionalHeader = &pNtHeaders->OptionalHeader;
if( (char*) p >= (char*)hDll && (char*) p <= ((char*)hDll) + pOptionalHeader->SizeOfCode )
// Sounds like valid address.
return p;
// Does not sounds right, may be someone hooked given function ? (ConEmuHk64.dll or ConEmuHk.dll)
IMAGE_DATA_DIRECTORY* pDataDirectory = &pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
IMAGE_EXPORT_DIRECTORY* pExp = (IMAGE_EXPORT_DIRECTORY *) ((size_t) pDosHeader + pDataDirectory->VirtualAddress);
ULONG* addrofnames = (ULONG *) ((BYTE*) hDll + pExp->AddressOfNames);
ULONG* funcaddr = (ULONG*) ((BYTE*) hDll + pExp->AddressOfFunctions);
for ( DWORD i = 0; i < pExp->NumberOfNames; i++ )
{
char* funcname = (char*) ((BYTE*) hDll + addrofnames[i]);
if ( strcmp( funcname, funcName ) == 0 )
{
ULONG addressOfFunction = funcaddr[i];
void* p2 = (void*) ((BYTE*) hDll + addressOfFunction);
if( addressOfFunction >= pDataDirectory->VirtualAddress && addressOfFunction < pDataDirectory->VirtualAddress + pDataDirectory->Size )
{
// "Exported function forward" - address of function can be found in another module.
// Actually for example AddDllDirectory is truly located in KernelBase.dll (alias api-ms-win-core-libraryloader-l1-1-0.dll ?)
char* dll_func = (char*) p2;
char* pdot = strchr(dll_func, '.');
if( !pdot ) pdot = dll_func + strlen( dll_func );
CStringA dllName(dll_func, (int)(pdot - dll_func));
dllName += ".dll";
HMODULE hDll2 = GetModuleHandleA(dllName);
if( hDll2 == NULL )
return p;
return GetProcAddress2( hDll2, pdot + 1 );
}
return (FARPROC) p2;
}
} //for
return p;
} //GetProcAddress2
除此之外,仍有可能将 .dll 加载到不同的地址,但这不会发生在 kernel32.dll 或 kernelbase.dll。
但是如果 .dll 变基成为问题 - 一种解决方法是使用 EasyHook 方法 - 可以在此处找到:
参见函数 GetRemoteFuncAddress。