BaseFiberStart Hooker

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by 0x0c0de, 17 Mar 2009.

  1. 0x0c0de

    0x0c0de Elder - Старейшина

    Joined:
    25 May 2007
    Messages:
    441
    Likes Received:
    395
    Reputations:
    297
    Ничего принципиально нового, но кому-то вероятно будет интересно. Речь здесь пойдет о волокнах. Поток в винде начинается с BaseThreadStartThunk, процесс с BaseProcessStartThunk, а волокно с BaseFiberStart. Значит, чтобы выполнить свой код до запуска кода волокна надо изменить эту неэкспортируемую функу BaseFiberStart. Сделать это просто, особенно в случае с волокнами. Кратко поясню как

    Посмотрим на прототип функции CreateFiber

    Code:
    
    LPVOID WINAPI CreateFiber(
      __in      SIZE_T dwStackSize,
      __in      LPFIBER_START_ROUTINE lpStartAddress,
      __in_opt  LPVOID lpParameter
    );
    
    

    Возвращаемое значение - адрес волокна. Что такое адрес волокна? А вот тут уже msdn ничего не скажет. Ну ок, берем IDA и начинаем дизасмить kernel32.dll.

    Для начала разберемся с WindowsXP SP3

    CreateFiber вызывает CreateFiberEx, а в CreateFiberEx вызывается _BaseInitializeContext@20. BaseInitializeContext как раз и определяет какой адрес записать BaseThreadStartThunk, BaseProcessStartThunk или BaseFiberStart. В качестве первого параметра эта функция принимает указатель на структуру CONTEXT.

    Как видим в структуре CONTEXT BaseFiberStart кладется по смещению 0B8h.

    Code:
    ifFiber:                                ; CODE XREF: BaseInitializeContext(x,x,x,x,x)+4C4F j
    .text:7C82FF6E                 mov     dword ptr [eax+0B8h], offset _BaseFiberStart@0 ; BaseFiberStart()
    .text:7C82FF78                 jmp     loc_7C8104A4
    
    Однако, взглянув на код вызова BaseInitializeContext можно увидеть, что на самом деле структура CONTEXT сама находиться по смещению 0x14h в другой структуре, которую и возвращает функция CreateFiber. А значит адрес BaseFiberStart находиться в этой структуре по смещению 0x14 + 0xb8 = 0xCC.

    Code:
    .text:7C830031                 push    2
    .text:7C830033                 mov     [esi+10h], ecx
    .text:7C830036                 push    [ebp+var_C]
    .text:7C830039                 push    [ebp+arg_C]
    .text:7C83003C                 push    eax
    .text:7C83003D                 lea     eax, [esi+14h]
    .text:7C830040                 push    eax
    .text:7C830041                 call    _BaseInitializeContext@20 ; BaseInitializeContext(x,x,x,x,x)
    .text:7C830046                 mov     eax, esi
    

    Таким образом мы вызываем CreateFiber, берем адрес волокна и меняем адрес по смещению 0xCC. Но на самом деле это круто только для WinXP. В висте и семерке все несколько иначе:

    CreateFiber->CreateFiberEx-> _BaseInitializeFiberContext@16

    А там уже по смещению 0xC4 кладется адрес, а по этому адресу уже лежит BaseFiberStart.

    Code:
    .text:77E02070                 mov     [esi+0C4h], eax
    .text:77E02076                 mov     dword ptr [eax], offset _BaseFiberStart@0 ; BaseFiberStart()
    
    Так что теперь непосредственно 0xC4 + 0x14 = 0xd8. И меняем адрес по этому адресу. Вот такие дела.

    И непосредственно кодес

    Code:
    #include "stdafx.h"
    #include <windows.h>
    
    extern "C"
    {
    LPVOID WINAPI CreateFiber(
      __in      SIZE_T dwStackSize,
      __in      PVOID lpStartAddress,
      __in_opt  LPVOID lpParameter
    );
    
    
    VOID WINAPI DeleteFiber(
      __in  LPVOID lpFiber
    );
    
    
    VOID WINAPI SwitchToFiber(
      __in  LPVOID lpFiber
    );
    
    LPVOID WINAPI ConvertThreadToFiber(
      __in_opt  LPVOID lpParameter
    );
    
    BOOL WINAPI ConvertFiberToThread(void);
    
    }
    
    PVOID pMainFiber,TrueBaseFiberStart;
    
    VOID _declspec(naked) NewBaseFiberStart(VOID)
    {
    	MessageBox(0,L"Fiber hooked",L"Hooked",0);
    
    	_asm
    	{
    		jmp [TrueBaseFiberStart]
    
    		ret
    	}
    }
    
    
    VOID StartFiber(VOID)
    {
    	PVOID pCurFiber;
    
    	printf("StartFiber: I am in fiber\n");
    
    	pCurFiber = GetCurrentFiber();
    
    	printf("StartFiber: current fiber 0x%08X\n",pCurFiber);
    
    	SwitchToFiber(pMainFiber);
    }
    
    BOOL HookBaseFiberStart(PVOID pFiber,PVOID pAddressNewBaseFiberStart,PDWORD pdwSaveAddress)
    {
    
    	BOOL bRes=FALSE;
    
    	DWORD dwVersion;
    
    	dwVersion = GetVersion();
    
    		//учитываем на какой системе мы
    
    		switch(LOBYTE(LOWORD(dwVersion)))
    		{
    
    			// модифицируем  _BaseFiberStart
    
    			case 5:
    
    				// до Vista
    				_asm
    				{
    
    					mov edi,pFiber
    
    					mov esi,dword ptr [edi + 0xcc]
    
    					mov eax,pdwSaveAddress
    					
    					mov dword ptr [eax], esi
    
    					mov esi,pAddressNewBaseFiberStart
    
    					mov dword ptr [edi + 0xcc],esi
    
    
    				}
    
    				bRes = TRUE;
    
    				break;
    
    				// начиная с Vista
    			case 6:
    
    				_asm
    				{
    					mov edi,pFiber
    
    					mov esi,dword ptr [edi+ 0xD8]
    
    					mov edi,dword ptr [esi]
    
    					mov eax, pdwSaveAddress
    
    					mov dword ptr [eax],edi
    
    					mov edi,pAddressNewBaseFiberStart
    
    					mov dword ptr [esi],edi
    				}
    
    				bRes = TRUE;
    
    				break;
    
    			default: break;
    	
    		}
    
    return bRes;
    
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	LPVOID pFiber;
    
    	// создаем волокно
    
    	pFiber = CreateFiber(0,&StartFiber,0);
    	
    	if(!pFiber)
    	{
    		printf ("Cannot create fiber\n");
    	}
    	else
    	{
    		
    		if(!HookBaseFiberStart(pFiber,NewBaseFiberStart,(PDWORD)&TrueBaseFiberStart))
    		{
    			return -1;
    		}
    
    
    		// делаем тред волокном, так как только волокно может запустить другое волокно
    
    		pMainFiber = ConvertThreadToFiber(0);
    
    		// запускаем наше свежесозданное волокно
    
    		SwitchToFiber(pFiber);
    
    		ConvertFiberToThread(); 
    
    		// удаляем волокно
    
    		printf("Deleting fiber 0x%08X...\n",pFiber);
    
    		DeleteFiber(pFiber);
    	}
    
    
    	Sleep(-1);
    
    	return 0;
    }
    
    

    В принципе можно применить в какой-нибудь защите.
     
    #1 0x0c0de, 17 Mar 2009
    Last edited: 17 Mar 2009
    3 people like this.
  2. De-visible

    De-visible [NDC] Network develope c0ders

    Joined:
    6 Jan 2008
    Messages:
    916
    Likes Received:
    550
    Reputations:
    66
    Я походу нуб, не понял вообще о чем речь... эх...
     
    1 person likes this.