CreateRemoteThread - Exception im Remote Thread



  • hallöchen,

    mein Vorhaben ist es, eigenen Code in einen fremden Prozess mittels der Funktion CreateRemoteThread einzuschleusen. Dazu allokiere ich Speicher im Prozess mit VirtualAllocEx für den Code und ein Struct, das als Argument übergeben wird.

    Das ist mein Struct, das als Argument übergeben wird:

    typedef HINSTANCE	(WINAPI *pLoadLibFunc)(PCSTR);
    typedef HINSTANCE	(WINAPI *pGetProcAddrFunc)(HMODULE,PCSTR);
    typedef HINSTANCE	(WINAPI *pFreeLibFunc)(HMODULE);
    typedef BOOL	     (WINAPI *pBeepFunc)(DWORD,DWORD);
    
    struct ThreadData {
        pLoadLibFunc pLoadLibrary;
        pGetProcAddrFunc pGetProcAddress;
        pFreeLibFunc pFreeLibrary;
        pBeepFunc pBeep;
        pSleepFunc pSleep;
        pVoidFunc pDebugBreak;
        //pDllFunc pHalloDllMain;
        //CHAR strDllPath[30];
        //CHAR strDllPath[30];
        //CHAR strDllFuncName[30];
        //CHAR strFuncName[30];
        //PVOID pUserData;
    };
    

    Meine Funktion, die injected wird, sieht wie folgt aus:

    static DWORD WINAPI ThreadStart(ThreadData* pData ) {
    	//pData->pDebugBreak();
    
    	__asm {
    		NOP
    		NOP
    		NOP
    		NOP
    		NOP
    	}
    
    	pData->pBeep(700,1000);
    
    	__asm {
    		NOP
    		NOP
    		NOP
    		NOP
    		NOP
    	}
    
        return 123;
    }
    

    Beim Aufruf der CreateRemoteThread-Funktion, die ich an calc.exe ausprobiert habe, höre ich das Piepen und danach kommt es in calc.exe zu einem Speicherzugriffsfehler. In der Disassembly sieht meine eingeschleuste Funktion so aus:

    003A0058  push        ebp  
        003A0059  mov         ebp,esp 
        003A005B  sub         esp,0CCh 
        003A0061  push        ebx  
        003A0062  push        esi  
        003A0063  push        edi  
        003A0064  lea         edi,[ebp-0CCh] 
        003A006A  mov         ecx,33h 
        003A006F  mov         eax,0CCCCCCCCh 
        003A0074  rep stos    dword ptr [edi] 
        003A0076  nop              
        003A0077  nop              
        003A0078  nop              
        003A0079  nop              
        003A007A  nop              
        003A007B  mov         esi,esp 
        003A007D  push        3E8h 
        003A0082  push        2BCh 
        003A0087  mov         eax,dword ptr [ebp+8] 
        003A008A  call        dword ptr [eax+0Ch] 
        003A008D  cmp         esi,esp 
        003A008F  call        003A0556 
        003A0094  mov         dword ptr [ebp-8],eax 
        003A0097  nop              
        003A0098  nop              
        003A0099  nop              
        003A009A  nop              
        003A009B  nop              
        003A009C  mov         eax,7Bh 
        003A00A1  pop         edi  
        003A00A2  pop         esi  
        003A00A3  pop         ebx  
        003A00A4  add         esp,0CCh 
        003A00AA  cmp         ebp,esp 
        003A00AC  call        003A0556 
        003A00B1  mov         esp,ebp 
        003A00B3  pop         ebp  
        003A00B4  ret         4    
        003A00B7  int         3
    

    Der Fehler tritt beim Aufruf der Funktion 003A0556 auf, da an der Stelle nur Nullbytes im Speicher sind.
    Wäre schön, wenn jemand eine Erklärung dafür hat, warum der Compiler diese seltsamen Funktionsaufrufe dort eingebaut hat, ich habe sämtliche Optimierungen, etc deaktiviert.

    Danke schonmal im Voraus 🙂

    PS: Ich habe nicht vor, Malware zu programmieren, bin hier nur ein bisschen am Rumprobieren 😉



  • Ich hatte mit Remote-Threads ein ähnliches Problem.
    Ich habs so gelöst:
    😉 Ich starte den Thread und lade eine von mir geschriebene DLL
    😉 In der DLL kann ich dann belibigen code von mir aus führen

    hier der Code dazu: (für VC++)

    So geht der Aufruf:

    RmtResetParam();
    RmtSetCallType(TYPE_CDECL);
    RmtAddParam("Hallo");

    // void __cdecl meine_funktion(char *text) in meine.dll aufrufen
    bOk=RmtStart("calc.exe","meine.dll","meine_funktion");

    //*****************************************************************************
    //*
    //*
    //*		RemoteThread.h
    //*
    //*
    //*****************************************************************************
    #ifndef 	__REMOTETHRED_H__
    #define 	__REMOTETHRED_H__
    
    	BOOL	RmtStart (DWORD  dwProcess,LPCSTR pDllName,LPCSTR pProcName,HANDLE *pHandel=0);
    	BOOL	RmtStart (HANDLE hProcess ,LPCSTR pDllName,LPCSTR pProcName,HANDLE *pHandel=0);
    	BOOL	RmtStart (LPCSTR pProcess ,LPCSTR pDllName,LPCSTR pProcName,HANDLE *pHandel=0);
    
    	VOID	RmtSetCallType(int iType);
    	VOID	RmtResetParam();
    	BOOL	RmtAddValue(DWORD  dwParam);
    	BOOL	RmtAddParam(void  *pParam);
    	BOOL	RmtAddParam(LPCSTR pParam);
    	BOOL	RmtAddParam(void  *pParam,unsigned uSize);
    
    	#ifndef	TYPE_CDECL
    	#define TYPE_CDECL		0
    	#endif
    	#ifndef	TYPE_STDCALL
    	#define TYPE_STDCALL	1
    	#endif
    
    #endif
    
    //*****************************************************************************
    //*
    //*
    //*     RemoteThread.cpp
    //*
    //*
    //*****************************************************************************
    #include    <stddef.h>
    #include    <string.h>
    #include    <windows.h>
    #include    <tlhelp32.h>
    #include    "RemoteThread.h"
    
    typedef int         (WINAPI *TypMessageBoxA)(HWND,LPCTSTR,LPCTSTR,UINT);
    typedef HMODULE     (WINAPI *TypGetModuleHandleA)(LPCTSTR);
    typedef HINSTANCE   (WINAPI *TypLoadLibraryA)(LPCTSTR);
    typedef BOOL        (WINAPI *TypFreeLibrary)(HMODULE);
    typedef FARPROC     (WINAPI *TypGetProcAddressA)(HMODULE,LPCSTR);
    
    #define     PROC_SIZE   0x10000
    #define     DATA_SIZE   0x1000
    #define     MAX_PARAM   8
    
    typedef struct
        {
        HMODULE             hKernel32;              // HMODULE von Kernel32.dll
        char                cDllName[256];          // Name der zu ladenden Dll
        char                cProcName[64];          // Name der Prozedur in der Dll
        TypFreeLibrary      FreeLibrary;            // Zeiger auf FreeLibrary
        TypLoadLibraryA     LoadLibrary;            // Zeiger auf LoadLibraryA
        TypGetProcAddressA  GetProcAddress;         // Zeiger auf GetProcAddress
        unsigned char       ucData[DATA_SIZE];      // Lokaler Datenspeicher für Parameter
        DWORD               dwParam[MAX_PARAM];     // Parameter
        int                 iParamCount;            // Anzahl der übergabe Parameter
        int                 iCallType;              // 0=cdecl 1=stdcall
        }LocalData;
    
    static  unsigned char   ucData[DATA_SIZE];      // Speicher für Parameter
    static  unsigned int    uiDataOffset=0;         // Offset im Speicher
    static  unsigned int    uiParamCount=0;         // Anzahl der Parameter
    static  unsigned int    uiParamData[MAX_PARAM]; // Werte der Parameter
    static  unsigned int    uiParamType[MAX_PARAM]; // 0=Wert 1=Pointer
    static  unsigned int    uiCallType=0;           // 0=cdecl 1=stdcall
    
    //*****************************************************************************
    //*
    //*     RmtThreadProc
    //*
    //*****************************************************************************
    static __declspec(naked) DWORD __stdcall WINAPI RmtThreadProc(LPVOID pParam)
    {
    
    _asm{
        push    ebp                                 ;// Initialisiere Stack
        mov     ebp,esp                             ;//     *
        mov     ecx,[ebp+8]                         ;// Hole pParam
    
        mov     eax,[ecx]LocalData.LoadLibrary      ;// Dll laden
        lea     ebx,[ecx]LocalData.cDllName         ;//         *
        push    ecx                                 ;//         *
        push    ebx                                 ;//         *
        call    eax                                 ;//         *
        pop     ecx                                 ;//         *
        cmp     eax,0                               ;//         *
        je      J3                                  ;//         *
    
        mov     edx,[ecx]LocalData.GetProcAddress   ;// Prozeturadresse laden
        lea     ebx,[ecx]LocalData.cProcName        ;//         *
        push    ecx                                 ;//         *
        push    ebx                                 ;//         *
        push    eax                                 ;//         *
        call    edx                                 ;//         *
        pop     ecx                                 ;//         *
        cmp     eax,0                               ;//         *
        je      J3                                  ;//         *
    
        cmp     [ecx]LocalData.iCallType,0          ;// Welcher Prozetur Typ
        push    ecx                                 ;//         *
        jne     J2                                  ;//         *
    
        mov     ebp,ecx                             ;// CDECL Prozetur starten
        lea     ebx,[ecx]LocalData.dwParam          ;//         *
        mov     ecx,[ecx]LocalData.iParamCount      ;//         *
        lea     ebx,[ebx+ecx*4-4];                  ;//         *
        jcxz    cc                                  ;//         *
    cn: push    [ebx]                               ;//         *
        sub     ebx,4                               ;//         *
        loop    cn                                  ;//         *
    cc: call    eax                                 ;//         *
        mov     edx,[ebp]LocalData.iParamCount      ;//         *
        shl     edx,2                               ;//         *
        add     esp,edx                             ;//         *
        pop     ecx                                 ;//         *
        jmp     J3                                  ;//         *
    
    J2: lea     ebx,[ecx]LocalData.dwParam          ;// STDCALL Prozetur starten
        mov     ecx,[ecx]LocalData.iParamCount      ;//         *
        lea     ebx,[ebx+ecx*4-4];                  ;//         *
        jcxz    sc                                  ;//         *
    sn: push    [ebx]                               ;//         *
        sub     ebx,4                               ;//         *
        loop    sn                                  ;//         *
    sc: call    eax                                 ;//         *
        pop     ecx                                 ;//         *
    
    J3: pop     ebp                                 ;// Register wieder herstellen
        ret     4                                   ;//         *
        }
    
    }
    
    //*****************************************************************************
    //*
    //*     RmtSetCallType
    //*
    //*****************************************************************************
    //  Die Aufrufart für die Dll Funktion festlegen
    //  iType   : 0=cdecl 1=stdcall
    //              TYPE_CDECL
    //              TYPE_STDCALL
    VOID RmtSetCallType(int iType)
    {
        uiCallType=iType;
    }
    
    //*****************************************************************************
    //*
    //*     RmtResetParam
    //*
    //*****************************************************************************
    //  Rücksetzen aller Parameter
    VOID RmtResetParam()
    {
        uiParamCount=0;
        uiDataOffset=0;
    }
    
    //*****************************************************************************
    //*
    //*     RmtAddValue
    //*
    //*****************************************************************************
    //  Anhängen eines Zahlen-Parameters
    //  Ergibt TRUE wenn erfolgreich
    BOOL RmtAddValue(DWORD  dwParam)
    {
    
        if(uiParamCount>=MAX_PARAM)return FALSE;
    
        uiParamData[uiParamCount]   = dwParam;
        uiParamType[uiParamCount]   = 0;
        uiParamCount++;
    
    return TRUE;
    }
    
    //*****************************************************************************
    //*
    //*     RmtAddParam
    //*
    //*****************************************************************************
    //  Anhängen eines Zeiger-Parameters
    //  Ergibt TRUE wenn erfolgreich
    BOOL RmtAddParam(void *pParam)
    {
    
        if(uiParamCount>=MAX_PARAM)return FALSE;
    
        uiParamData[uiParamCount]   = (DWORD)pParam;
        uiParamType[uiParamCount]   = 0;
        uiParamCount++;
    
    return TRUE;
    }
    
    //*****************************************************************************
    //*
    //*     RmtAddParam
    //*
    //*****************************************************************************
    //  Anhängen eines Zeiger-Parameters
    //  Ergibt TRUE wenn erfolgreich
    BOOL RmtAddParam(LPCSTR pParam)
    {
        return RmtAddParam((void*)pParam,strlen(pParam)+1);
    
    return TRUE;
    }
    
    BOOL RmtAddParam(void  *pParam,unsigned int uSize)
    {
    
        if(uiParamCount>=MAX_PARAM)return FALSE;
        if(uiDataOffset+uSize>DATA_SIZE)return FALSE;
    
        uiParamData[uiParamCount]   = uiDataOffset;
        uiParamType[uiParamCount]   = 1;
        uiParamCount++;
    
        memcpy(ucData+uiDataOffset,pParam,uSize);
    
        uiDataOffset+=uSize;
        uiDataOffset+=3;
        uiDataOffset&=~3;
    
    return TRUE;
    }
    
    //*****************************************************************************
    //*
    //*     RmtStart
    //*
    //*****************************************************************************
    //  Startet den einen Remote Thread
    //  dwProcess   : Process ID des Prozesses in dem der Thread gestartet wird
    //  hProcess    : Process Handle des Prozesses in dem der Thread gestartet wird
    //  pDllName    : Name der Dll die geladen wird
    //  pProcName   : Name der Prozedur die gestartet wird
    //  pHandel     : Wenn ungleich 0 dann wird heir das Thread Handle gespeichert
    //                  (ab Win2000)
    //  Ergibt TRUE wenn erfolgreich
    BOOL RmtStart(LPCSTR pProcess,LPCSTR pDllName,LPCSTR pProcName,HANDLE *pHandel)
    {
    BOOL            bOk=FALSE;
    HANDLE          hSnapshot;
    PROCESSENTRY32  sData;
    
        hSnapshot=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
    
        sData.dwSize=sizeof(sData);
        if(!Process32First(hSnapshot,&sData))return FALSE;
    
        do  {
            if(stricmp(pProcess,sData.szExeFile))continue;
            bOk=RmtStart(sData.th32ProcessID,pDllName,pProcName);
            break;
            }while(Process32Next(hSnapshot,&sData));
    
        CloseHandle(hSnapshot);
    
    return bOk;
    }
    
    BOOL RmtStart(DWORD  dwProcess,LPCSTR pDllName,LPCSTR pProcName,HANDLE *pHandel)
    {
    BOOL    bOk;
    HANDLE  hProcess;
    
            hProcess=OpenProcess(PROCESS_ALL_ACCESS|PROCESS_VM_OPERATION| PROCESS_VM_READ | PROCESS_VM_WRITE,TRUE,dwProcess);
        if(!hProcess)return FALSE;
    
        bOk=RmtStart(hProcess,pDllName,pProcName,pHandel);
    
        CloseHandle(hProcess);
    
    return bOk;
    }
    
    BOOL RmtStart(HANDLE hProcess,LPCSTR pDllName,LPCSTR pProcName,HANDLE *pHandel)
    {
    LPVOID          pProc,pLocal;
    DWORD           dwBytes,dwId;
    LocalData       sLocal;
    HANDLE          hThread;
    int             i;
    
            pProc=VirtualAllocEx(hProcess,NULL,PROC_SIZE,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
        if(!pProc)return FALSE;
    
            pLocal=VirtualAllocEx(hProcess,NULL,sizeof(LocalData),MEM_COMMIT,PAGE_READWRITE);
        if(!pLocal)
            {
            VirtualFreeEx(hProcess,pProc,PROC_SIZE,MEM_RELEASE);
            return FALSE;
            }
    
        memset(&sLocal,0,sizeof(sLocal));
    
        sLocal.hKernel32        = GetModuleHandle("KERNEL32");
        sLocal.FreeLibrary      = (TypFreeLibrary     )GetProcAddress(sLocal.hKernel32,"FreeLibrary");
        sLocal.LoadLibrary      = (TypLoadLibraryA    )GetProcAddress(sLocal.hKernel32,"LoadLibraryA");
        sLocal.GetProcAddress   = (TypGetProcAddressA )GetProcAddress(sLocal.hKernel32,"GetProcAddress");
    
        strncpy(sLocal.cDllName ,pDllName ,sizeof(sLocal.cDllName )-1);
        strncpy(sLocal.cProcName,pProcName,sizeof(sLocal.cProcName)-1);
        memcpy (sLocal.ucData,ucData,uiDataOffset);
    
        sLocal.iCallType=uiCallType;                // 0=cdecl 1=stdcall
        sLocal.iParamCount=uiParamCount;
    
        for(i=0;i<sLocal.iParamCount;i++)
            {
            sLocal.dwParam[i]=uiParamData[i];
            if(uiParamType[i])sLocal.dwParam[i]+=(DWORD)pLocal+offsetof(LocalData,ucData);
            }
    
        if(!WriteProcessMemory(hProcess,pProc,RmtThreadProc,PROC_SIZE,&dwBytes))
            {
            VirtualFreeEx(hProcess,pLocal,sizeof(LocalData),MEM_RELEASE);
            VirtualFreeEx(hProcess,pProc ,PROC_SIZE,MEM_RELEASE);
            return FALSE;
            }
    
        if(!WriteProcessMemory(hProcess,pLocal,&sLocal,sizeof(LocalData),&dwBytes))
            {
            VirtualFreeEx(hProcess,pLocal,sizeof(LocalData),MEM_RELEASE);
            VirtualFreeEx(hProcess,pProc ,PROC_SIZE,MEM_RELEASE);
            return FALSE;
            }
    
            hThread=CreateRemoteThread(hProcess,0,0x40000,(LPTHREAD_START_ROUTINE)pProc,pLocal,0,&dwId);
        if(!hThread)return FALSE;
    
        if(pHandel)*pHandel=hThread;
        else    CloseHandle(hThread);
    
    return TRUE;
    }
    

    Meine Homepage:

    http://members.inode.at/anton.zechner/az/index.html



  • ja, danke erstmal

    Ich hatte ja auch vor, eine DLL zu laden und dann die Hautpfunktion aus der DLL aufzurufen. Dafür müssen aber erstmal meine Funktionspointer auf GetProcAddress, LoadLibrary und FreeLibrary funktionieren. Die Beep-Funktion funktioniert ja in meinem Fall auch, das einzige Problem ist der Funktionsaufruf in's Nichts, den VS.NET 2003 (ohne optimierungen) dort einfügt. Du hast ja dieses Problem nicht, weil du es in Assembler gemacht hast

    Naja, werde ich mal weitersehen oder deinen Loader verwenden 😃



  • Ich habe das Problem jetzt gelöst. Die Funktion, die aufgerufen wurde, war _RTC_CheckEsp, da ich versehentlich bei der Release-Projektkonfiguration die falschen Einstellungen gewählt habe. Und der Pointer ist natürlich im anderen Prozess nicht gültig. Jetzt funktioniert alles wie erwartet.


Anmelden zum Antworten