使用代码注入在远程进程中执行函数

Executing function in remote process using code injection

本文关键字:进程 函数 执行 程进程 代码 注入      更新时间:2023-10-16

我使用高级代码注入代码在远程进程上启动.dll。你可以从这里找到它是如何工作的/代码片段:

https://sourceforge.net/p/diagnostic/svn/HEAD/tree/src/RemoteInit.cpp

我注意到,对于某些应用程序,这种方法不起作用——它会使主机应用程序崩溃。主要问题似乎是特殊类型的第三方软件,如ConEmuHk64.dll,它通过提供自己的钩子函数来拦截kernel32.dll GetProcAddress -之后,我得到这样的函数指针:

*((FARPROC*) &info.pfuncGetProcAddress) = GetProcAddress(hKernel32, "GetProcAddress");

但相反,我得到指向ConEmuHk64.dll中的函数的指针。

在我自己的进程中调用该函数是可以接受的,但是当试图在远程进程中做同样的事情时-它会崩溃,因为ConEmuHk64.dll不一定在那里可用。

我已经找出了如何通过手动在DOS/NE其他标头中行走来自动探测该函数的正确地址的机制-这里是代码片段:

//
//  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返回DOS头之前的地址。

我怀疑dll/代码大小范围的比较是不正确的:

    if( (char*) p >= (char*)hDll && (char*) p <= ((char*)hDll) + pOptionalHeader->SizeOfCode )

但我不知道如何改进配方。

你能给我推荐一下如何完全修复这个问题吗-这样任何第三方软件都可以拦截任何功能,我也可以从它那里生存下来而不会崩溃?

函数指针解析是不正确的,如果使用"导出函数向前"(可以通过该术语搜索)。

一个合适的函数解析可以这样写:(你在上面看到的是从某个论坛复制粘贴的函数)

//
//  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方法-可以位于这里:

https://github.com/EasyHook/EasyHook/blob/b8b2e37cfe1c269eea7042420bde305eb127c973/EasyHookDll/RemoteHook/thread.c