地理信息系统知识库gisbase

http://www.cnblogs.com/gisbase
  新随笔  :: 联系 :: 订阅 订阅  :: 管理

获取其它进程内EDIT BOX内容的一种方法

Posted on 2011-01-20 11:41  gisbase  阅读(516)  评论(5编辑  收藏  举报

获取其它进程内EDIT BOX内容的一种方法

呕心沥血写就(试验代码写了一大坨),修改及转载请标明出处,谢谢!

感谢[jozu][ahakin][辟邪马甲]等高手指点。

GetWindowText等函数在win2k及以后系统上不能获得其它进程内的EDIT BOX内容,本文使用CreateRemoteThread来解决这个问题。
* 这不是唯一的解决方法,使用钩子等方法也可以解决这个问题。
* 即使使用CreateRemoteThread,那么注入自己的DLL会简单一箩筐,但我这里没有使用自己的DLL,所以这是一种很差的方法,代码移植性差、代码编写复杂、代码不容易看懂,等等,但它也有一个优点:不需要制作自己的DLL ^_^。
(不需要制作自己的DLL有另外一个大优点,不说)

平台:IBM兼容PC指令, Windows 2K pro
编译器:VC++6.0
说明:
1. 欲在目标进程内使用GetWindowText等函数,必先加载User32.dll。
* 如果目标进程早已自己加载了User32的话,再加载一次也无所妨 ^_^
2. 载入User32.dll需要用到LoadLibrary等,其存在于KERNEL32.DLL中。
* KERNEL32.DLL是内核模块,无需显式载入。
3. CreateRemoteThread可以自带一个参数,而LoadLibrary也只需要一个参数,因此可以使用一点点技巧令目标进程载入User32.dll。
* CreateRemoteThread( , , , &LoadLibraryA, 动态库名称, ,  );
4. CALL和JMP等指令后面的是相对偏移,因此代码中存在CALL和LONG JMP时需要重新调整相对偏移。
* CALL指令格式:
* Y : ……
* X : CALL Y
* 生成的指令就是
* E8, Y-X-5
* 可见CALL指令跟其所处地址是有关系的,因此将CALL Y移到新地址后要重新计算Y-X-5。
5. 因为要调整CALL后的相对便宜,因为我使用汇编来编写线程函数。
* 编译器不对汇编语句进行任何优化和调整
6. 在DEBUG下,自己定义的函数其函数地址处是个jmp,跳到真正的函数体处,所以不能简单的使用 &函数名称 来得到地址,但如果定义这个全局函数为static可以不生成jmp,可惜这里的代码写在类中,因为还是需要自己去计算真正的地址。
7. 此处使用"USER32"来令目标进程载入USER32.DLL,这不是一种保稳的做法。保稳的做法是使用全路径,令目标进程无法"作弊" ^_^

代码如下,没有过多测试
#include <windows.h>
#include <cassert>

class CRemoteEditBox
{
public:
    static DWORD GetPIdFromCtrl( HWND hCtrl );
    CRemoteEditBox( DWORD dwRemoteProcessId = 0 );
    ~CRemoteEditBox();
    bool Open( DWORD dwRemoteProcessId );
    void Close();
    bool IsOpen() const;
    int GetTextLength( HWND hEdit ) const;
    bool GetText( HWND hEdit, char* pStr, int nLen ) const;
    bool SetText( HWND hEdit, const char* pStr );
private:
    static DWORD __stdcall _GetTextLength( LPVOID lpParam );
    static DWORD __stdcall _GetText( LPVOID lpParam );
    static DWORD __stdcall _SetText( LPVOID lpParam );
    static VOID  __stdcall _EndText( LPVOID lpParam );
private:
    CRemoteEditBox( const CRemoteEditBox& );
    CRemoteEditBox& operator=( const CRemoteEditBox& );
private:
    DWORD PId;
    HANDLE hProcess;
    mutable void* pData;
    void* pCode;
    HINSTANCE hInst;
    mutable size_t DataLen;
};

DWORD CRemoteEditBox::GetPIdFromCtrl( HWND hCtrl )
{
    DWORD PId = 0;
    GetWindowThreadProcessId( hCtrl, &PId );
    return PId;
}

CRemoteEditBox::CRemoteEditBox( DWORD dwRemoteProcessId )
{
    PId = 0;
    hProcess = 0;
    pData    = 0;
    pCode    = 0;
    hInst    = 0;
    DataLen  = 0;
    Open( dwRemoteProcessId );
}

CRemoteEditBox::~CRemoteEditBox()
{
    Close();
}

__declspec(naked) DWORD __stdcall CRemoteEditBox::_GetTextLength( LPVOID lpParam )
{
    __asm mov eax, [esp+4]
    __asm push eax
    __asm call GetWindowTextLengthA
    __asm ret 4
}
__declspec(naked) DWORD __stdcall CRemoteEditBox::_GetText( LPVOID lpParam )
{
    __asm mov eax, [esp+4]
    __asm push [eax+4]
    __asm add eax, 8
    __asm push eax
    __asm sub eax, 8
    __asm push [eax]
    __asm call GetWindowTextA
    __asm ret 4
}
__declspec(naked) DWORD __stdcall CRemoteEditBox::_SetText( LPVOID lpParam )
{
    __asm mov eax, [esp+4]
    __asm add eax, 4
    __asm push eax
    __asm sub eax, 4
    __asm push [eax]
    __asm call SetWindowTextA
    __asm ret 4
}
void __stdcall CRemoteEditBox::_EndText( LPVOID lpParam )
{
}
bool CRemoteEditBox::Open( DWORD dwRemoteProcessId )
{
    Close();
    if( 0 == dwRemoteProcessId ) return false;

    PId = dwRemoteProcessId;
    hProcess = ::OpenProcess( PROCESS_ALL_ACCESS, TRUE, PId );
    if( 0 != hProcess )
    {
        char USER32[] = "USER32";
        DataLen = 65536;
        pData = VirtualAllocEx( hProcess, 0, DataLen, MEM_COMMIT, PAGE_READWRITE );
        if( 0 != pData )
        {
            WriteProcessMemory( hProcess, pData, USER32, sizeof(USER32), NULL );
            HANDLE hThread = CreateRemoteThread( hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)&LoadLibraryA, pData, 0, NULL );
            if( 0 != hThread )
            {
                WaitForSingleObject( hThread, INFINITE );
                GetExitCodeThread( hThread, (DWORD*)&hInst );
                ::CloseHandle( hThread );
                if( 0 != hInst )
                {
#ifdef _DEBUG // DEBUG 下函数多了一个jmp
                    const DWORD __GetTextLength = *(LPDWORD)((LPBYTE)(&_GetTextLength)+1) + (DWORD)(&_GetTextLength) + 5;
                    const DWORD __GetText = *(LPDWORD)((LPBYTE)(&_GetText)+1) + (DWORD)(&_GetText) + 5;
                    const DWORD __SetText = *(LPDWORD)((LPBYTE)(&_SetText)+1) + (DWORD)(&_SetText) + 5;
                    const DWORD __EndText = *(LPDWORD)((LPBYTE)(&_EndText)+1) + (DWORD)(&_EndText) + 5;
#else
                    const DWORD __GetTextLength = (DWORD)(&_GetTextLength);
                    const DWORD __GetText = (DWORD)(&_GetText);
                    const DWORD __SetText = (DWORD)(&_SetText);
                    const DWORD __EndText = (DWORD)(&_EndText);
#endif
                    const size_t CODELEN1 = __GetText - __GetTextLength;
                    const size_t CODELEN2 = __SetText - __GetText;
                    const size_t CODELEN3 = __EndText - __SetText;
                    const size_t CODELEN = __EndText - __GetTextLength;

                    pCode = VirtualAllocEx( hProcess, 0, CODELEN, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
                    if( 0 != pCode )
                    {
                        // 重定向
                        char CODE[512];
                        memcpy( CODE, (const void*)__GetTextLength, CODELEN );
                        LPBYTE p = 0;
                        for( p=(LPBYTE)CODE; (BYTE)0xE8!=*p; ++p ); // E8为CALL指令
                        *(DWORD*)(p+1) = (DWORD)&GetWindowTextLength - (DWORD)(p-(LPBYTE)CODE+(LPBYTE)pCode) - 5;
                        for( p=(LPBYTE)CODE+CODELEN1; (BYTE)0xE8!=*p; ++p );
                        for( ++p; (BYTE)0xE8!=*p; ++p );
                        *(DWORD*)(p+1) = (DWORD)&GetWindowText - (DWORD)(p-(LPBYTE)CODE+(LPBYTE)pCode) - 5;
                        for( p=(LPBYTE)CODE+CODELEN1+CODELEN2; (BYTE)0xE8!=*p; ++p );
                        for( ++p; (BYTE)0xE8!=*p; ++p );
                        *(DWORD*)(p+1) = (DWORD)&SetWindowText - (DWORD)(p-(LPBYTE)CODE+(LPBYTE)pCode) - 5;

                        WriteProcessMemory( hProcess, pCode, CODE, CODELEN, NULL);
                        return true;

                        VirtualFreeEx( hProcess, pCode, 0, MEM_RELEASE );
                        pCode = 0;
                    }
                    hThread = CreateRemoteThread( hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)&FreeLibrary, hInst, 0, NULL );
                    if( 0 != hThread )
                    {
                        WaitForSingleObject( hThread, INFINITE );
                        ::CloseHandle( hThread );
                    }
                    hInst = 0;
                }
            }
            VirtualFreeEx( hProcess, pData, 0, MEM_RELEASE );
            pData = 0;
        }
        DataLen = 0;
        CloseHandle( hProcess );
        hProcess = 0;
    }
    PId = 0;
    return false;
}

void CRemoteEditBox::Close()
{
    if( 0 != PId )
    {
        HANDLE hThread = CreateRemoteThread( hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)&FreeLibrary, hInst, 0, NULL );
        if( 0 != hThread )
        {
            WaitForSingleObject( hThread, INFINITE );
            ::CloseHandle( hThread );
        }
        hInst = 0;

        VirtualFreeEx( hProcess, pCode, 0, MEM_RELEASE );
        VirtualFreeEx( hProcess, pData, 0, MEM_RELEASE );
        CloseHandle( hProcess );
        PId      = 0;
        hProcess = 0;
        pData    = 0;
        pCode    = 0;
        DataLen  = 0;
    }
}

bool CRemoteEditBox::IsOpen() const
{
    return ( 0 != hProcess );
}

int CRemoteEditBox::GetTextLength( HWND hEdit ) const
{
    assert( IsOpen() );
    assert( GetPIdFromCtrl(hEdit) == PId );

    int ret = 0;
    HANDLE hThread = CreateRemoteThread( hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pCode, hEdit, 0, NULL );
    if( 0 != hThread )
    {
        WaitForSingleObject( hThread, INFINITE );
        GetExitCodeThread( hThread, (DWORD*)&ret );
        ::CloseHandle( hThread );
    }
    return ret;
}

bool CRemoteEditBox::GetText( HWND hEdit, char* pStr, int nLen ) const
{
    assert( IsOpen() );
    assert( GetPIdFromCtrl(hEdit) == PId );

    if( sizeof(hEdit)+sizeof(nLen)+nLen+1 >= DataLen )
    {
        DataLen = ( sizeof(hEdit)+sizeof(nLen)+nLen+1 + 65535 )/65536 * 65536;
        VirtualFreeEx( hProcess, pData, 0, MEM_RELEASE );
        pData = VirtualAllocEx( hProcess, 0, DataLen, MEM_COMMIT, PAGE_READWRITE );
        if( 0 == pData )
        {
            DataLen = 0;
            return false;
        }
    }
    WriteProcessMemory( hProcess, pData, &hEdit, sizeof(hEdit), NULL );
    WriteProcessMemory( hProcess, (LPBYTE)pData+sizeof(hEdit), &nLen, sizeof(nLen), NULL );

#ifdef _DEBUG
    const DWORD __GetTextLength = *(LPDWORD)((LPBYTE)(&_GetTextLength)+1) + (DWORD)(&_GetTextLength) + 5;
    const DWORD __GetText = *(LPDWORD)((LPBYTE)(&_GetText)+1) + (DWORD)(&_GetText) + 5;
#else
    const DWORD __GetTextLength = (DWORD)(&_GetTextLength);
    const DWORD __GetText = (DWORD)(&_GetText);
#endif
    int ret = 0;
    LPTHREAD_START_ROUTINE p = (LPTHREAD_START_ROUTINE)( (LPBYTE)pCode + (__GetText-__GetTextLength) );
    HANDLE hThread = CreateRemoteThread( hProcess, NULL, 0, p, pData, 0, NULL );
    if( 0 != hThread )
    {
        WaitForSingleObject( hThread, INFINITE );
        GetExitCodeThread( hThread, (DWORD*)&ret );
        ::CloseHandle( hThread );
        ReadProcessMemory( hProcess, (char*)pData+sizeof(hEdit)+sizeof(nLen), pStr, nLen, NULL );
        return true;
    }
    return false;
}

bool CRemoteEditBox::SetText( HWND hEdit, const char* pStr )
{
    assert( IsOpen() );
    assert( GetPIdFromCtrl(hEdit) == PId );

    size_t nLen = strlen(pStr)+1;
    if( sizeof(hEdit)+nLen+1 >= DataLen )
    {
        DataLen = ( sizeof(hEdit)+nLen+1 + 65535 )/65536 * 65536;
        VirtualFreeEx( hProcess, pData, 0, MEM_RELEASE );
        pData = VirtualAllocEx( hProcess, 0, DataLen, MEM_COMMIT, PAGE_READWRITE );
        if( 0 == pData )
        {
            DataLen = 0;
            return false;
        }
    }
    WriteProcessMemory( hProcess, pData, &hEdit, sizeof(hEdit), NULL );
    WriteProcessMemory( hProcess, (LPBYTE)pData+sizeof(hEdit), (void*)pStr, nLen, NULL );

#ifdef _DEBUG
    const DWORD __GetTextLength = *(LPDWORD)((LPBYTE)(&_GetTextLength)+1) + (DWORD)(&_GetTextLength) + 5;
    const DWORD __SetText = *(LPDWORD)((LPBYTE)(&_SetText)+1) + (DWORD)(&_SetText) + 5;
#else
    const DWORD __GetTextLength = (DWORD)(&_GetTextLength);
    const DWORD __SetText = (DWORD)(&_SetText);
#endif
    int ret = 0;
    LPTHREAD_START_ROUTINE p = (LPTHREAD_START_ROUTINE)( (LPBYTE)pCode + (__SetText-__GetTextLength) );
    HANDLE hThread = CreateRemoteThread( hProcess, NULL, 0, p, pData, 0, NULL );
    if( 0 != hThread )
    {
        WaitForSingleObject( hThread, INFINITE );
        GetExitCodeThread( hThread, (DWORD*)&ret );
        ::CloseHandle( hThread );
        return true;
    }
    return false;
}

// 测试代码
#include <stdio.h>
int main( void )
{
    HWND hEdit = (HWND)0x0013047A; // 自己找个EDIT BOX的HANDLE
    CRemoteEditBox a;
    if( a.Open( CRemoteEditBox::GetPIdFromCtrl(hEdit) ) )
    {
        char tmp[260];
        printf( "length = %u\n", a.GetTextLength(hEdit) );
        a.GetText( hEdit, tmp, 260 );
        printf( "str = %s\n\n", tmp );

        a.SetText( hEdit, "A1B2C3" );

        printf( "length = %u\n", a.GetTextLength(hEdit) );
        a.GetText( hEdit, tmp, 260 );
        printf( "str = %s\n\n", tmp );
    }
}