Results 1 to 12 of 12

Thread: "Client" Unit Tests(some fun ones..)Indirect RtlCreateUserThread hooking..

  1. #1
    |< x != '+' BanMe's Avatar
    Join Date
    Oct 2008
    Location
    Farmington NH
    Posts
    510
    Blog Entries
    4

    "Client" Unit Tests(some fun ones..)Indirect RtlCreateUserThread hooking..

    code called before RtlCreateUserThread ..
    Code:
    if(InitUserHooks(ClientView))
    {
    	Status = RtlCreateUserThread(NtCurrentProcess(),0,0,0,0,0,(PUSER_THREAD_START_ROUTINE)wtf,0,&PortHandle,&Cid);
    }
    InitUserHooks..
    Code:
    BOOL InitUserHooks(PORT_VIEW CodeView)
    {
    	ULONG Addr_BaseThreadStart = 0;
    	ULONG Addr_BaseThreadStartThunk = 0;
    	ULONG Addr_LdrInitializeThread = 0;
    	ULONG Addr_LdrCallInitRoutine = 0;
    	BYTE SigBaseThread[7] = { 0x33,0xED,0x53,0x50,0x6A,0x00,0xE9 };
    	BYTE SigLdrInitializeThread[9] = { 0x6A, 0x02, 0xFF, 0x76, 0x10, 0xFF, 0x75, 0xE0, 0xE8 };
    	BYTE CodBaseThread[2] = { 0x00,0x00};
    	BYTE CodLdrCallInit[5] = { 0x00,0x00};
    	NTSTATUS Status = 0;
    	ULONG NumOfBytes = 2;
    	PVOID pfnOrigin = 0;
    	int i;
    	GetProcessModules();
    	for(i = 0;i<20;i++)
    	{
    		if(wcscmp((PWSTR)Array_ModName[i], L"ntdll.dll") == 0)
    			break;
    	}
    	Addr_LdrInitializeThread = SigSeek_FindCode((DWORD)Array_ModHandle[i],((DWORD)Array_ModHandle[i]+Array_ModSize[i]),sizeof(SigLdrInitializeThread),(DWORD*)&SigLdrInitializeThread);
    	if(Addr_LdrInitializeThread)
    	{
    		__asm
    		{
    			mov ebx,[eax+0x9]
    			add ebx,eax
    			add ebx,0xd
    			mov Addr_LdrCallInitRoutine,ebx
    		}
    	}
    	else
    	{
    		return FALSE;
    	}
    	for(i = 0;i<20;i++)
    	{
    		if(wcscmp((PWSTR)Array_ModName[i], L"kernel32.dll") == 0)
    			break;
    	}
    	Addr_BaseThreadStartThunk = SigSeek_FindCode((DWORD)Array_ModHandle[i],((DWORD)Array_ModHandle[i]+Array_ModSize[i]),sizeof(SigBaseThread),(DWORD*)&SigBaseThread);
    	if(Addr_BaseThreadStartThunk)
    	{
    		// extract the address of kernel32.BaseThreadStart() from jmp instruction
    		// destination = code location + jump offset + 5
    		__asm
    		{
    			mov ebx, [eax+7]
    			add ebx, eax // code location
    			add ebx, 6 // 
    			add ebx, 5
    			mov Addr_BaseThreadStart, ebx
    		}
    	}
    	else
    	{
    		return FALSE;
    	}
    	ULONG Hook_LdrCallInitRoutine = ((ULONG)CodeView.ViewBase);
    	if(Native_HotPatchAddrEx(Addr_LdrCallInitRoutine,Hook_LdrCallInitRoutine,0x1DEB,1,&pfnOrigin))
    	{
    		return TRUE;
    	}
    	return FALSE;
    }
    Native_HotPatchAddrEx
    Code:
    bool Native_HotPatchAddrEx(ULONG oldProc, ULONG newProc,WORD Code,ULONG NumOfNop, void**ppOrigFn)
    {
    	bool bRet = false;
        ULONG oldProtect = NULL;
    	ULONG pLongJump = 0;
    	ULONG pLongJumpAdr = 0;
    	ULONG ProtectSize = 2;
    	ULONG ProtectAddr = oldProc;
    	BYTE Nop = 0x90;
    	if(!NT_SUCCESS(NtProtectVirtualMemory(NtCurrentProcess(),(PVOID*)&ProtectAddr, &ProtectSize, PAGE_EXECUTE_READWRITE, &oldProtect)))
    	{
    		return bRet;
    	}
    	WORD *pJumpBack = (WORD*)oldProc;
    	__asm
    	{
    		lea ecx,Code
    		inc ecx
    		mov al,byte ptr[ecx];
    		movzx ecx,al
    		cmp ecx,0
    		je Failed 
    		push ecx
    		add oldProc,ecx
    		push oldProc
    		pop ProtectAddr
    		mov ProtectSize,5
    	}
    	if(!NT_SUCCESS(NtProtectVirtualMemory(NtCurrentProcess(),(PVOID*)&ProtectAddr,&ProtectSize,PAGE_EXECUTE_READWRITE,&oldProtect)))
    	{
    		return bRet;
    	}
    	__asm
    	{
    		pop ecx
    		push oldProc
    		pop pLongJump
    		inc oldProc
    		push oldProc		
    		pop pLongJumpAdr
    		dec oldProc
    		sub oldProc,ecx
    	 	
    	}
    	if(*pJumpBack != 0xFF8B)
    	{
    		__asm
    		{
    			add oldProc,2
    			mov edi,oldProc
    			lea esi,Nop
    			mov ecx,NumOfNop
    			rep movsb
    			sub oldProc,2
    		}
    	}
        *(BYTE*)pLongJump = 0xE9;    // long jmp
        *(ULONG*)pLongJumpAdr = (newProc - oldProc)-0x22;    // 
        *pJumpBack = 0x1beb;        // short jump back -7 (back 5, plus two for this jump)
        if (ppOrigFn)
    	{
    		*ppOrigFn = ((BYTE*)oldProc);
    		bRet = true;
    	}
      	//if(!NT_SUCCESS(NtProtectVirtualMemory(NtCurrentProcess(),(PVOID*)&pLongJump, &ProtectSize, oldProtect, &oldProtect)))
    	//{
    	//	return bRet;
    	//}
    Failed:
    	return bRet;
    }
    LdrpCallInitRoutine after hooking..
    Code:
    _LdrpCallInitRoutine@16:
      jmp         _LdrpCallInitRoutine@16+1Dh (7C901193h) 
      nop              
      push        esi  
      push        edi  
      push        ebx  
      mov         esi,esp 
      push        dword ptr [ebp+14h] 
      push        dword ptr [ebp+10h] 
      push        dword ptr [ebp+0Ch] 
      call        dword ptr [ebp+8] 
      mov         esp,esi 
      pop         ebx  
      pop         edi  
      pop         esi  
      pop         ebp  
      ret         10h  
      jmp         01570000
    Code in "Shared" Mapped View (originates in server)..
    Code:
    		XOR ECX,ECX
    QSFRA:
    		MOV EAX,[ESP+(ECX*0x4)]
    		CMP EAX,0x7c900000
    		JL IncStack
    		CMP EAX,0x7cA00000
    		JG IncStack
    RDUNOP:
    		CMP WORD PTR [EAX],0x406a
    		JE FAS
    	    SUB EAX,1
    		JMP RDUNOP
    FAS:
    		PUSH EBP
    		MOV EBP,ESP
    		MOV EAX,0x7c901179
    		JMP EAX
    IncStack:
    		INC ECX
    		JMP QSFRA
    		ret
    code executed after call of RtlCreateUserThread by LdrpCallInitRoutine..

    Code:
    __DllMainCRTStartupForGS@12:
      mov         edi,edi 
      push        ebp  
      mov         ebp,esp 
      cmp         dword ptr [ebp+0Ch],1 
      je          __DllMainCRTStartupForGS@12+0Bh (7C9222FAh) 
      xor         eax,eax 
      inc         eax  
      pop         ebp  
      ret         0Ch
    hmm
    Code:
    _BaseDllInitialize@12:
      mov         edi,edi 
      push        ebp  
      mov         ebp,esp 
      cmp         dword ptr [ebp+0Ch],1 
      je          _BaseDllInitialize@12+0Bh (7C818A92h) 
      pop         ebp  
      nop              
      nop              
      nop              
      nop              
      nop              
    __BaseDllInitialize@12:
      mov         edi,edi 
      push        ebp  
      mov         ebp,esp 
      sub         esp,424h 
      mov         eax,dword ptr [___security_cookie (7C8856CCh)] 
      mov         ecx,dword ptr [ebp+8] 
      push        ebx  
      push        esi  
      push        edi  
      xor         edi,edi 
      mov         dword ptr [ebp-4],eax 
      mov         dword ptr [ebp-424h],ecx 
      mov         dword ptr [ebp-414h],edi 
      mov         eax,dword ptr fs:[00000018h] 
      mov         eax,dword ptr [eax+30h] 
      mov         eax,dword ptr [eax+1D4h] 
      mov         dword ptr [_SessionId (7C8856E4h)],eax 
      mov         dword ptr [_BaseDllHandle (7C885054h)],ecx 
      mov         eax,dword ptr fs:[00000018h] 
      mov         ebx,dword ptr [eax+30h] 
      mov         eax,dword ptr [ebp+0Ch] 
      sub         eax,edi 
      mov         dword ptr [ebp-420h],ebx 
      je          7C81CAF4 
      dec         eax  
      je          __BaseDllInitialize@12+89h (7C8185EDh) 
      dec         eax  
      jne         __BaseDllInitialize@12+61h (7C80C177h) 
      push        edi  
      push        2    
      call        _ConDllInitialize@8 (7C80B777h) 
      test        al,al 
      je          __BaseDllInitialize@12+82h (7C82B7ECh) 
      mov         al,1 
      mov         ecx,dword ptr [ebp-4] 
      pop         edi  
      pop         esi  
      pop         ebx  
      call        @__security_check_cookie@4 (7C8097AAh) 
      leave            
      ret         0Ch
    then goes on to deactivate Activation Context, it also leaves Ldr Critical Section..and then finally ZwTestAlert.. which calls the routine of RtlCreateUserThread..hope some of this was 'fun' .. ;p

    regards BanMe

  2. #2
    |< x != '+' BanMe's Avatar
    Join Date
    Oct 2008
    Location
    Farmington NH
    Posts
    510
    Blog Entries
    4

    Test 2 Native APC Injection..P.O.C. based off of some conficker stuffs..

    this is current non working code even in my environment I cannot get it to break on the APC's code in the View..im not sure why yet..wtf is still called so ZwTestAlert was called...this needs a more 'dynamic' way to make the calls but i know this..its a test and you might be a 'computer ghost' or some fictitious 'bot' gathering keywords or calculating a decision tree,or you might be researching the 'next' release of 'conficker or some other virii' or w/e. I just learn and bring it down..to my level..I guess..

    on with the code..

    Server Lpc Message Handler Routine
    Code:
    		Status = NtReplyWaitReceivePort(ClientHandle,NULL,NULL,&RecvMessage);
    		if(!NT_SUCCESS(Status))
    		{
    #ifdef __DEBUG__
    			RtlInitUnicodeString(&Unicode,L"NtReplyWaitRecievePort Status ");
    			Write_Debug(&Unicode,Status);
    #endif
    			return false;
    		}
    		SizeHk = GetFunctionLength(CatchInit);
    		if(!SizeHk)
    		{
    
    #ifdef __DEBUG__
    			RtlInitUnicodeString(&Unicode,L"Failed Retrieving Length ");
    			Write_Debug(&Unicode,Status);
    #endif
    			RecvMessage.u2.s2.Type = LPC_ERROR_EVENT;
    			NtReplyPort(ClientHandle,&RecvMessage);
    			return false;
    		}
    		//memcpy((void*)ClientView.ViewBase,0,sizeof(ULONG));
    		//memcpy((void*)ClientView.ViewBase+0x4,0,sizeof(ULONG));
    		//memmove((void*)ClientView.ViewBase,(void*)&Reusable,sizeof(ULONG));
    		memcpy((void*)((ULONG)ClientView.ViewBase),(void*)CatchInit,SizeHk);
    		wcscpy((wchar_t*)((ULONG)ClientView.ViewBase+SizeHk+2),L"user32.dll");
    		SizeFn = GetFunctionLength(Native_ApcLoadRoutine);
    		memcpy((void*)((ULONG)ClientView.ViewBase+SizeHk+2+wcslen(L"user32.dll")+2),Native_ApcLoadRoutine,SizeFn);
    		if(!SizeFn)
    		{
    #ifdef __DEBUG__
    			RtlInitUnicodeString(&Unicode,L"Failed Retrieving Length");
    			Write_Debug(&Unicode,Status);
    #endif
    			RecvMessage.u2.s2.Type = LPC_ERROR_EVENT;
    			NtReplyPort(ClientHandle,&RecvMessage);
    			return false;
    		}
    		ClientId.UniqueThread = RecvMessage.ClientId.UniqueThread;
    		oa.Length = sizeof(OBJECT_ATTRIBUTES);
    		Status = NtOpenThread(&Reusable,THREAD_ALL_ACCESS,&oa,&ClientId);
    		Status = NtQueueApcThread(Reusable,(PIO_APC_ROUTINE)((ULONG)ClientView.ViewBase+SizeHk+2+wcslen(L"user32.dll")+2),(PVOID)((ULONG)ClientView.ViewBase+SizeHk+2),&Ios,0);
    		Status = NtReplyPort(ClientHandle, &RecvMessage);
    The APC to load a dll (code wont work unless you call the functions dynamically and 'injected before ZwTestAlert...)I dont do either here..though

    Code:
    void Native_ApcLoadRoutine(PVOID p1,PIO_STATUS_BLOCK p2,ULONG Reserved)
    {
    	HANDLE User32 = 0;
    	UNICODE_STRING Unicode = {0};
    	RtlInitUnicodeString(&Unicode,(wchar_t*)p1);
    	LdrLoadDll(0,0,&Unicode,&User32);
    	return;
    }
    I still need to make it break at the proper location..evil conficker! lol...

    BanMe
    Last edited by BanMe; August 29th, 2009 at 17:50.
    No hate for the lost children;
    more love for the paths we walk,
    'words' shatter the truth we seek.
    from the heart and mind of Me
    me, to you.. down and across

    No more words from me, to you...
    Hate and love shatter the heart and Mind of Me.
    For the Lost Children;For the paths we walk; the real truth we seek!

  3. #3
    Teach, Not Flame Kayaker's Avatar
    Join Date
    Oct 2000
    Posts
    4,084
    Blog Entries
    5
    Hi BanMe.

    So um, to clarify, are you saying that you can't get it to break in the APC code, but the APC still runs and the dll is loaded?

    I've done the same thing actually, inject a dll by issuing an APC which runs LdrLoadDll, except strictly from kernel mode - the APC runs as a mapped MDL in the target process address space.


    APC's (think of an APC as a Callback routine) are rather cool because you can pass up to 3 user defined variables which you can use in the APC routine. I see you've used one, the name of the dll. Perhaps you can get a bit more flexibility if you can make use of the other two opportunities.



    Here's a bit of info and stuff, forgive me if it's redundant or whatever.


    First take a look at the definition of NtQueueApcThread. I use the one from

    http://www.ddj.com/windows/184416590?pgno=6

    Code:
    NtQueueApcThread (
    	IN HANDLE Thread,
    	IN PKNORMAL_ROUTINE NormalRoutine,
    	IN PVOID NormalContext,
    	IN PVOID SystemArgument1,
    	IN PVOID SystemArgument2
    	);

    And here is the prototype of the user mode APC routine (this is comparable to your Native_ApcLoadRoutine, though not quite the same prototype):

    void APCNormalRoutine(PVOID pNormalContext, PVOID pSystemArgument1, PVOID pSystemArgument2);


    Note how the 3 parameters provided to NtQueueApcThread are passed to the APC routine. Within NtQueueApcThread, the first parameter, NormalContext, is handled by KeInitializeApc. The other two (SystemArgument1/2) are handled by KeInsertQueueApc.

    If you look at NtQueueApcThread, you've pretty much got the procedure for issuing a usermode APC from kernel mode.


    Here are the prototypes I use.


    Code:
    extern "C"
    {
    	#include "ntddk.h"
    }
    
    
    /* Function prototypes for APCs
    
    	From James Antognini APC techniques article
    	http://home.mindspring.com/~antognini/drivers/APCDrv.zip
    	(see also "Inside NT's Asynchronous Procedure Call," Albert Almedia,
    	WinDeveloperNet, November 2002)
    
    */
    
    
    typedef enum _KAPC_ENVIRONMENT
      {
       OriginalApcEnvironment,
       AttachedApcEnvironment,
       CurrentApcEnvironment
      }
    KAPC_ENVIRONMENT;
    
    
    typedef CHAR KPROCESSOR_MODE;
    
    typedef enum _MODE
            {
    /*000*/ KernelMode,
    /*001*/ UserMode,
    /*002*/ MaximumMode
            }
            MODE,
         * PMODE,
        **PPMODE;
    
    
    
    EXTERN_C
    NTKERNELAPI
    VOID
    KeInitializeApc(
                    IN PRKAPC Apc,
                    IN PKTHREAD Thread,
                    IN KAPC_ENVIRONMENT Environment,
                    IN PKKERNEL_ROUTINE KernelRoutine,
                    IN PKRUNDOWN_ROUTINE RundownRoutine OPTIONAL,
                    IN PKNORMAL_ROUTINE NormalRoutine OPTIONAL,
                    IN KPROCESSOR_MODE ApcMode,
                    IN PVOID NormalContext
                   );
    
    EXTERN_C
    NTKERNELAPI
    BOOLEAN
    KeInsertQueueApc(
                     IN PRKAPC Apc,
                     IN PVOID SystemArgument1,
                     IN PVOID SystemArgument2,
                     IN KPRIORITY Increment
                    );
    
    typedef
    VOID
    (*PKKERNEL_ROUTINE) (
        IN struct _KAPC *Apc,
        IN OUT PKNORMAL_ROUTINE *NormalRoutine,
        IN OUT PVOID *NormalContext,
        IN OUT PVOID *SystemArgument1,
        IN OUT PVOID *SystemArgument2
        );
    
    typedef
    VOID
    (*PKRUNDOWN_ROUTINE) (
        IN struct _KAPC *Apc
        );
    
    typedef
    VOID
    (*PKNORMAL_ROUTINE) (
        IN PVOID NormalContext,
        IN PVOID SystemArgument1,
        IN PVOID SystemArgument2
        );

    And here is NtQueueApcThread defined:

    Code:
    0050CB8D ; int __stdcall NtQueueApcThread(HANDLE Thread, PKNORMAL_ROUTINE NormalRoutine, PVOID NormalContext, PVOID SystemArgument1, PVOID SystemArgument2)
    0050CB8D _NtQueueApcThread@20 proc near          ; DATA XREF: .text:0040DB80o
    0050CB8D
    0050CB8D AccessMode      = byte ptr -4
    0050CB8D Thread          = dword ptr  8
    0050CB8D NormalRoutine   = dword ptr  0Ch
    0050CB8D NormalContext   = dword ptr  10h
    0050CB8D SystemArgument1 = dword ptr  14h
    0050CB8D SystemArgument2 = dword ptr  18h
    0050CB8D
    0050CB8D ; FUNCTION CHUNK AT 0052E12E SIZE 00000025 BYTES
    0050CB8D
    0050CB8D                 mov     edi, edi
    0050CB8F                 push    ebp
    0050CB90                 mov     ebp, esp
    0050CB92                 push    ecx
    0050CB93                 push    ebx
    0050CB94                 push    esi
    0050CB95                 mov     eax, large fs:124h
    0050CB9B                 mov     al, [eax+140h]
    0050CBA1                 mov     [ebp+AccessMode], al
    0050CBA4                 xor     esi, esi
    0050CBA6                 push    esi             ; HandleInformation
    0050CBA7                 lea     eax, [ebp+Thread]
    0050CBAA                 push    eax             ; Object
    0050CBAB                 push    dword ptr [ebp+AccessMode] ; AccessMode
    0050CBAE                 push    _PsThreadType   ; ObjectType
    0050CBB4                 push    10h             ; DesiredAccess
    0050CBB6                 push    [ebp+Thread]    ; Handle
    0050CBB9                 call    _ObReferenceObjectByHandle@24 ; ObReferenceObjectByHandle(x,x,x,x,x,x)
    0050CBBE                 mov     ebx, eax
    0050CBC0                 cmp     ebx, esi
    0050CBC2                 jl      short loc_50CC25
    0050CBC4                 mov     eax, [ebp+Thread]
    0050CBC7                 xor     ebx, ebx
    0050CBC9                 test    byte ptr [eax+248h], 10h
    0050CBD0                 jnz     loc_52E12E
    0050CBD6                 push    edi
    0050CBD7                 push    'pasP'          ; Tag
    0050CBDC                 push    30h             ; NumberOfBytes
    0050CBDE                 push    8               ; PoolType
    0050CBE0                 call    _ExAllocatePoolWithQuotaTag@12 ; ExAllocatePoolWithQuotaTag(x,x,x)
    0050CBE5                 mov     edi, eax
    0050CBE7                 cmp     edi, esi
    0050CBE9                 jz      loc_52E138
    0050CBEF                 push    [ebp+NormalContext] ; NormalContext
    0050CBF2                 push    1               ; ApcMode
    0050CBF4                 push    [ebp+NormalRoutine] ; NormalRoutine
    0050CBF7                 push    esi             ; RundownRoutine
    0050CBF8                 push    offset _IopDeallocateApc@20 ; KernelRoutine
    0050CBFD                 push    esi             ; Environment
    0050CBFE                 push    [ebp+Thread]    ; Thread
    0050CC01                 push    edi             ; Apc
    0050CC02                 call    _KeInitializeApc@32 ; KeInitializeApc(x,x,x,x,x,x,x,x)
    0050CC07                 push    esi             ; Increment
    0050CC08                 push    [ebp+SystemArgument2] ; SystemArgument2
    0050CC0B                 push    [ebp+SystemArgument1] ; SystemArgument1
    0050CC0E                 push    edi             ; Apc
    0050CC0F                 call    _KeInsertQueueApc@16 ; KeInsertQueueApc(x,x,x,x)
    0050CC14                 test    al, al
    0050CC16                 jz      loc_52E142
    0050CC1C
    0050CC1C loc_50CC1C:                             ; CODE XREF: NtQueueApcThread(x,x,x,x,x)+215B0j
    0050CC1C                                         ; NtQueueApcThread(x,x,x,x,x)+215C1j
    0050CC1C                 pop     edi
    0050CC1D
    0050CC1D loc_50CC1D:                             ; CODE XREF: NtQueueApcThread(x,x,x,x,x)+215A6j
    0050CC1D                 mov     ecx, [ebp+Thread]
    0050CC20                 call    @ObfDereferenceObject@4 ; ObfDereferenceObject(x)
    0050CC25
    0050CC25 loc_50CC25:                             ; CODE XREF: NtQueueApcThread(x,x,x,x,x)+35j
    0050CC25                 pop     esi
    0050CC26                 mov     eax, ebx
    0050CC28                 pop     ebx
    0050CC29                 leave
    0050CC2A                 retn    14h
    0050CC2A _NtQueueApcThread@20 endp


    For comparison, here is some code which emulates NtQueueApcThread. The main difference is that you must deallocate the memory for the KAPC object yourself. This is done by the (PKKERNEL_ROUTINE) APCKernelRoutine, which will execute before either the user or kernel mode APC is actually run.


    Code:
    /**********************************************************
    			APCKernelRoutine
    
    	Kernel APC routine that runs before normal APC routine (user or kernel)
    	
    ***********************************************************/   
    
    void
    APCKernelRoutine(
                    IN PKAPC            pKAPC,
                    IN PKNORMAL_ROUTINE pUserAPC,
                    IN PVOID            pNormalContext,
                    IN PVOID            pSystemArgument1,
                    IN PVOID            pSystemArgument2
                   )
    {
    	
    //	DbgPrint("\nLPCHOOK: APCKernelRoutine Entered\n");
    //	DbgPrint("		pNormalContext = 0x%p\n", pNormalContext);
    //	DbgPrint("		pSysArg1   = 0x%p\n", pSystemArgument1);
    //	DbgPrint("		pSysArg2   = 0x%p\n", pSystemArgument2);
    
    	ExFreePool(pKAPC);
    
    	return;
    }
    Code:
    void QueueUserAPC(PVOID pUserAPCRoutine, 
                      ULONG pNormalContext,
                      ULONG pSystemArgument1,
                      ULONG pSystemArgument2)
    {
    
        PKTHREAD TargetThread = KeGetCurrentThread();
    	
        // Allocate space for KAPC object
    	
        pKAPC = (PKAPC) ExAllocatePool( NonPagedPool, sizeof(KAPC) );
        RtlZeroMemory(pKAPC, sizeof(KAPC));
    
    
        // Initialize the UserMode APC
    
        KeInitializeApc(
            pKAPC,
            TargetThread,
            OriginalApcEnvironment,             // * UserMode setting
            (PKKERNEL_ROUTINE)APCKernelRoutine,
            NULL,
            (PKNORMAL_ROUTINE) pUserAPCRoutine, // * UserMode setting (mapped MDL)
            UserMode,                           // * UserMode setting
            (PVOID)pNormalContext               // Context (first parameter to normal APC)
        );
    
    
        // Insert it to the queue of the target thread
    
        KeInsertQueueApc(
            pKAPC,
            (PVOID)pSystemArgument1,    // Context 2
            (PVOID)pSystemArgument2,    // Context 3
            0                           // Priority increment
        );
    
     
        /*
        Mark the thread as alertable to force it to deliver 
        the APC on the next return to the user-mode. 
    	
        Set KAPC_STATE.UserApcPending on.
        */
    
    
        *((unsigned char *)TargetThread+0x4a)=1; 
    
    }


    In my case the 3 variables I passed to the MDL memory mapped APC, and which accomplished the exact same thing as your APC, were

    pNormalContext = (ULONG) pLdrLoadDll; // pointer to LdrLoadDll
    pSystemArgument1 = (ULONG) pMappedData; // dll path in wide string format (in mapped MDL data section)
    pSystemArgument2 = (ULONG) unicodeLengthInfo; // UNICODE_STRING Length and MaximumLength



    Issuing a kernel mode APC is almost identical to that for a user mode APC, except that you would use different enum values for KAPC_ENVIRONMENT and KPROCESSOR_MODE with KeInitializeApc. As well you would NOT mark the kernel thread as alertable.

    Code:
    	
    // Initialize the KernelMode APC
    
    KeInitializeApc(
    	pKAPC,
    	TargetThread,
    	CurrentApcEnvironment,			// * KernelMode setting
    	(PKKERNEL_ROUTINE)APCKernelRoutine,
    	NULL,
    	(PKNORMAL_ROUTINE) APCNormalRoutine,    // * KernelMode setting
    	KernelMode,				// * KernelMode setting
    	(PVOID)pNormalContext  			// Context (first parameter to normal APC)
    );


    So all that said and done, it looks like you're using the old NtQueueApcThread prototype from

    http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/APC/NtQueueApcThread.html

    and that is where the PIO_STATUS_BLOCK parameter came from in your APC routine prototype.

    I'm not so sure I'd use that old definition, I'd be more inclined to trust Dr. Dobb's definition of NtQueueApcThread

    Cheers,
    Kayaker

  4. #4
    |< x != '+' BanMe's Avatar
    Join Date
    Oct 2008
    Location
    Farmington NH
    Posts
    510
    Blog Entries
    4
    yes and this is a excellent usermode example.. to compliment your kernel mode routines

    http://code.google.com/p/dynamorio/source/browse/trunk/suite/tests/security-win32/apc-shellcode.c?spec=svn128&r=128


    You are correct in assuming that I was using that prototype.. its hard to get away from 'undocumented' as alot of things i have learned has been with that sites help..but dr.dobbs definition looks just as good.. though not knowing exactly what the PVOID's are is somewhat annoying especially when coding with 'undocumented api'...

    I wanted to just be able to break at the APC's code (i know it wont load the dll successfully as the IAT wont match up..ie i place a breakpoint before call just to verify the code is actually run..) using the above example i should be able to finish this section of testing of APC and come up with various methods of APC activation.. thanks for the info kayaker ;}

    BanMe

    p.s. yea this is just the initial dev of this area of code..(P.O.C. and V.O.C.(Validity of Concept) come before dynamic and redundant additions..).. its all some fucked up dev process I like to adhere to.. ;] I want proof and confirmation of proof before investing my time into further development..

    p.p.s. nice use of QueueUserApcEx authors finding of how to forcefully process APC's

    Code:
    *((unsigned char *)TargetThread+0x4a)=1;
    im gonna use DUMKOM to do that as a last resort to forcing the target thread to be alertable..
    Last edited by BanMe; August 30th, 2009 at 19:21.
    No hate for the lost children;
    more love for the paths we walk,
    'words' shatter the truth we seek.
    from the heart and mind of Me
    me, to you.. down and across

    No more words from me, to you...
    Hate and love shatter the heart and Mind of Me.
    For the Lost Children;For the paths we walk; the real truth we seek!

  5. #5
    Teach, Not Flame Kayaker's Avatar
    Join Date
    Oct 2000
    Posts
    4,084
    Blog Entries
    5
    Quote Originally Posted by BanMe View Post
    as a last resort to forcing the target thread to be alertable..
    You could create/inject a dummy thread in an alertable state and issue as many APC's as required to that thread. Here is one created in that state permanently specifically for that use, but

    You could also monitor WaitForSingleObjectEx dwResult for WAIT_IO_COMPLETION - when an APC is queued to the thread.

    If you want to kill the thread without waiting for the target process to close, use SetEvent to signal the event. WaitForSingleObjectEx will return WAIT_OBJECT_0 and you can call ExitThread.


    Code:
    // Create a thread for handling APC
    
    Create_Thread((ULONG_PTR) &ApcAlertedThread, (void*)lParam);
    		
    		
    ///////////////////////////////////////////////////////
    void ApcAlertedThread(LPARAM lParam)
    {
    
    	DWORD dwResult; 
    	HANDLE hEvent;
    	
    	//////////////////////////////////////////////////
      
    __try{	
    
    	hEvent = CreateEvent(
    				NULL,   // LPSECURITY_ATTRIBUTES lpEventAttributes,
    				FALSE,  // BOOL bManualReset,
    				FALSE,  // BOOL bInitialState, non-signaled
    				NULL);	// LPCTSTR lpName
    				
    		
    	if (hEvent)
    	{
    		while (TRUE)
    		{
    			dwResult = WaitForSingleObjectEx(hEvent, INFINITE, TRUE);
    
    			if (dwResult != -1)
    			{		
    			
    			}
    		}
    			
    		CloseHandle(hEvent);
    	}
    
    
      ///////////////////////////////////////////////////  
    
    	}	// END try
    
    	// Exception handler
    	__except(ExceptCatch( GetExceptionCode(), GetExceptionInformation()))  {
    	
    	}
    	
    }
    
    ///////////////////////////////////////////////////////

    Quote Originally Posted by BanMe View Post
    though not knowing exactly what the PVOID's are is somewhat annoying especially when coding with 'undocumented api'...
    In this case they are just arbitrary user defined PVOIDS passed along blindly in the KAPC structure.

    Code:
    0:000> dt nt!_KAPC
    ntdll!_KAPC
       +0x000 Type             : Int2B
       +0x002 Size             : Int2B
       +0x004 Spare0           : Uint4B
       +0x008 Thread           : Ptr32 _KTHREAD
       +0x00c ApcListEntry     : _LIST_ENTRY
       +0x014 KernelRoutine    : Ptr32     void 
       +0x018 RundownRoutine   : Ptr32     void 
       +0x01c NormalRoutine    : Ptr32     void 
       +0x020 NormalContext    : Ptr32 Void
       +0x024 SystemArgument1  : Ptr32 Void
       +0x028 SystemArgument2  : Ptr32 Void
       +0x02c ApcStateIndex    : Char
       +0x02d ApcMode          : Char
       +0x02e Inserted         : UChar

  6. #6
    |< x != '+' BanMe's Avatar
    Join Date
    Oct 2008
    Location
    Farmington NH
    Posts
    510
    Blog Entries
    4

    Unit Test 2.1 Apc Dll Injection with LdrLoadDll

    Hi Kayaker,

    hmm that is interesting..I love blind parameters that have no form of sanitization capable of being applied to them..that is so yummy..

    but on with my bouncing..

    Native_ApcLoadRoutine designed to be totally self reliant after support routines run against it..
    APCs or Asynchronous Procedure Call's are queued to threads and executed upon the threads return to user mode.

    Code:
    void __declspec(naked)Native_ApcLoadRoutine(PVOID p1,PVOID p2,PVOID Reserved)
    {
    	__asm
    	{
    		jmp InitUnicode
    start:
    		nop //'U'
    		nop
    		nop //'s'
    		nop
    		nop //'e'
    		nop
    		nop //'r'
    		nop
    		nop //'3'
    		nop
    		nop //'2'
    		nop
    		nop //'.'
    		nop
    		nop //'d'
    		nop
    		nop //'l'
    		nop
    		nop //'l'
    		nop
    		nop //'0'
    		nop 
    UnicodeStr:
    		nop 
    		nop
    		nop
    		nop
    		nop
    		nop
    		nop
    		nop //0x1e
    InitUnicode:
    		lea eax,UnicodeStr//
    		lea ecx,start
    		push ecx
    		push eax
    		mov eax,0x7c901295
    		call eax
    		jmp LoadDll
    DllHandle:
    		nop
    		nop
    		nop
    		nop
    		nop
    		nop
    		nop
    		nop
    LoadDll:
    		lea eax,DllHandle
    		push eax
    		lea eax,UnicodeStr
    		push eax
    		push 0
    		push 0
    		mov eax,0x7c9163c3
    		call eax
    		ret
    	}
    }
    Support Routine gets the function length of Native_ApcLoadRoutine and changes the PAGE Protection to READWRITE
    and also writes the string that will be Initialized and used to inject the dll..
    Code:
    		SizeHk = GetFunctionLength(CatchInit);
    		SizeFn = GetFunctionLength(Native_ApcLoadRoutine);
    		if(!SizeHk && !SizeFn)
    		{
    
    #ifdef __DEBUG__
    			RtlInitUnicodeString(&Unicode,L"Failed Retrieving Length ");
    			Write_Debug(&Unicode,Status);
    #endif
    			RecvMessage.u2.s2.Type = LPC_ERROR_EVENT;
    			NtReplyPort(ClientHandle,&RecvMessage);
    			return false;
    		}
    		memcpy((void*)((ULONG)ClientView.ViewBase),(void*)CatchInit,SizeHk);
    		//ripped off hook hopping refurbished..
    		Reusable = (HANDLE)((ULONG)Native_ApcLoadRoutine+2);
    		SzProt = SizeFn;
    		Status = NtProtectVirtualMemory(NtCurrentProcess(),&Reusable,&SzProt,PAGE_READWRITE,&OldProt);
    		Reusable = (HANDLE)((ULONG)Native_ApcLoadRoutine+2);
    		wcscpy((wchar_t*)Reusable,User32);
    		memcpy((void*)((ULONG)ClientView.ViewBase+SizeHk+2),Native_ApcLoadRoutine,SizeFn);
    		ClientId.UniqueThread = RecvMessage.ClientId.UniqueThread;
    		oa.Length = sizeof(OBJECT_ATTRIBUTES);
    Result:fail

    immediate unload of the dll shows a problem somewhere..

    'SIN32.exe': Loaded 'C:WINDOWS\System32\SIN32.exe', Symbols loaded.
    'SIN32.exe': Loaded 'C:\WINDOWS\system32\ntdll.dll', Symbols loaded (source information stripped).
    'SIN32.exe': Loaded 'C:\WINDOWS\system32\kernel32.dll', Symbols loaded (source information stripped).
    'SIN32.exe': Loaded 'C:\WINDOWS\system32\user32.dll', Symbols loaded (source information stripped).
    'SIN32.exe': Loaded 'C:\WINDOWS\system32\gdi32.dll', No symbols loaded.
    'SIN32.exe': Unloaded 'C:\WINDOWS\system32\user32.dll'
    'SIN32.exe': Unloaded 'C:\WINDOWS\system32\gdi32.dll'

    ive added some dynamic stuff,not the funtion calls but the string stuff..dynamic function pointers will replace static function pointers after the dll stays loaded..

    anyone got any ideas on why it immediately unloads?
    No hate for the lost children;
    more love for the paths we walk,
    'words' shatter the truth we seek.
    from the heart and mind of Me
    me, to you.. down and across

    No more words from me, to you...
    Hate and love shatter the heart and Mind of Me.
    For the Lost Children;For the paths we walk; the real truth we seek!

  7. #7
    Teach, Not Flame Kayaker's Avatar
    Join Date
    Oct 2000
    Posts
    4,084
    Blog Entries
    5
    Now don't you go abusing no poor unsanitized parameters

    gdi32 is being loaded by user32 as part of the usual Ldrp_ initialization routines, or have you created a separate APC loading for gdi32? Since it seems to fail at gdi32 loading..and unwinds.. wondering about non-gui server thread as the parent, lack of Shadow SSDT, that sort of thing...? Guessing.

  8. #8
    |< x != '+' BanMe's Avatar
    Join Date
    Oct 2008
    Location
    Farmington NH
    Posts
    510
    Blog Entries
    4
    lol APC poisoning sounds like so much fun though..hard to resist..the temptation of something unvisited and unchecked..

    Maybe i should try a dll that doesnt load other dlls and go with just mapping user32 and creating a thread the runs the 'entrypoint' we talked of earliar..and no additional APC for GDI..damn thing autoloads..ill post the STATUS value and code up some further tests with different dll's to see if the same thing happens..

    I can't tell you how much i value your responses kayaker..truely you are what i aspire to be one day.. Thank you.

    BanMe
    Last edited by BanMe; September 2nd, 2009 at 00:58.
    No hate for the lost children;
    more love for the paths we walk,
    'words' shatter the truth we seek.
    from the heart and mind of Me
    me, to you.. down and across

    No more words from me, to you...
    Hate and love shatter the heart and Mind of Me.
    For the Lost Children;For the paths we walk; the real truth we seek!

  9. #9
    Teach, Not Flame Kayaker's Avatar
    Join Date
    Oct 2000
    Posts
    4,084
    Blog Entries
    5
    You mean a moderator of this board? Nah you wouldn't want it, the pay sucks. The company is good though.

    I just mess around with stuff, same as you. It's your kind of posts and new ways of thinking that make this place interesting. Keep up the Fractured Fairy Tales

    Kayaker

  10. #10
    BanMe you need to aim higher !!!!

    Aspire to be me, you can be an Admin and pay for the place .

    I used to hold dominion over the mods but I am sure they have installed their own "backdoors" to get back in should I delete them .

    Anyway, reading you two go back and forth on this makes me happy.
    Stimulates my "old" mind.

    Woodmann

  11. #11
    |< x != '+' BanMe's Avatar
    Join Date
    Oct 2008
    Location
    Farmington NH
    Posts
    510
    Blog Entries
    4
    I was aiming at his knowledge, one of the few things I hold above money.. ;}

    lol my fractured fairy tale continues regardless..

    Result: successful testing of phase 2 code..

    Code:
    void __declspec(naked)Native_ApcLoadRoutine(PVOID p1,PVOID p2,PVOID Reserved)
    {
    	__asm
    	{
    		jmp InitUnicode
    start:
    		nop //'U'
    		nop
    		nop //'s'
    		nop
    		nop //'e'
    		nop
    		nop //'r'
    		nop
    		nop //'3'
    		nop
    		nop //'2'
    		nop
    		nop //'.'
    		nop
    		nop //'d'
    		nop
    		nop //'l'
    		nop
    		nop //'l'
    		nop
    		nop //'0'
    		nop 
    UnicodeStr:
    		nop 
    		nop
    		nop
    		nop
    		nop
    		nop
    		nop
    		nop //0x1e
    InitUnicode:
    		lea eax,UnicodeStr//
    		lea ecx,start
    		push ecx
    		push eax
    		mov eax,0x7c901295
    		call eax
    		jmp LoadDll
    DllHandle:
    		nop
    		nop
    		nop
    		nop
    Hack:
    		nop
    		nop
    		nop
    		nop
    LoadDll:
    		lea eax,DllHandle
    		push eax
    		lea eax,UnicodeStr
    		push eax
    		lea eax,Hack
    		xor ecx,ecx
    		mov byte ptr [eax+ecx],0x3
    		inc ecx
    HackWrite:
    		cmp ecx,3
    		jg CompHack
    		mov byte ptr [eax+ecx],0x0
    		inc ecx
    		jmp HackWrite
    CompHack:
    		push eax
    		push 0
    		mov eax,0x7c9163c3
    		call eax
    		ret
    	}
    }
    figuring out how to pass a PULONG withing a naked function without globals and not using 0..lemme just say that was 'fun'..

    same support Routines as above..This loads a dll with LOAD_LIBRARY_AS_DATAFILE|DONT_RESOLVE_DLL_REFERENCES this is not good..but just makes the dll loaded,picking a appinit_dll at least taught me something..dont load these conventionally..figure out how the the system does it, and reproduce that in my own way..

    I think it easier to Map 'user32' into my context..and force A 'server' thread to just call the "entrypoint"..this works with other dll's other the appinit's!! without being loaded with all these issues raised by these previously mentioned constants and not really need 'the hack'.

    NtAlertResumeThread looks like a promising edition the threading part of my recycler.. I still have to make a effient cleanup system for the handletable..ive also been thinking each thread in the 'server' could maintain its own handle table which would speed up the queries each thread had to make using the handletable by not just lumping everything together..some of this time would get used by the 'additional' swapping routine but you wont notice it.

    I also think its time..I filled out more in how I am going to implement the client..further..

    My first thoughts where to hook 'base' routines in kernel32...(opcode0x90 did that..) and i found flaws then LdrpCallInitRoutine came as a excellent space to hook many of the aspects of a PE image loading and infact gather information about the 'clients' host application..but now I want something that nails it down..im going to hook LdrInitializeProcess to permenantly seal the initialization of my client into 'every process'..this is where 'having a output method of somekind and a input method of anykind would come in handy..so that is why I am interested in user32..i want to use a 'botting' technique using findwindow and automate a display from the server..hopefully providing input as well..good thing i did alot of research into how quizzywabbit did what he did in autoit..back when..and damn, im starting to think the later i stay up and 'more' tired i get, the more coherent my writing becomes..amazing..

    BanMe
    Last edited by BanMe; September 5th, 2009 at 06:03.
    No hate for the lost children;
    more love for the paths we walk,
    'words' shatter the truth we seek.
    from the heart and mind of Me
    me, to you.. down and across

    No more words from me, to you...
    Hate and love shatter the heart and Mind of Me.
    For the Lost Children;For the paths we walk; the real truth we seek!

  12. #12
    |< x != '+' BanMe's Avatar
    Join Date
    Oct 2008
    Location
    Farmington NH
    Posts
    510
    Blog Entries
    4
    so ive been reworking the Native_ApcLoadRoutine in added the dynamic address 'staticly' to the code dynamicly..if that makes sense..to anyone..
    and ive been really trying to keep the code as clean as possible.. for easier interpretation by my analyzers..and myself..But I hit the end of my knowledge tree and need nudge to fully understand the 'extent of my problem' or a hint to see that the way i solved it 'should be' working..

    the problem is with a 2 byte near jmp instruction being misinterpretted as a far jmp..here is the 'corrected' (as far as i can tell)code that upon analysis generates this issue.
    Code:
    RtlInit_U:
    00405280 95               xchg        eax,ebp 
    00405281 12 90 7C 00 C3 63 adc         dl,byte ptr [eax+63C3007Ch] 
    00405287 91               xchg        eax,ecx 
    00405288 7C 00            jl          Start (40528Ah) 
    Start:
    0040528A E9 0F 01 00 00   jmp         InitUnicode (40539Eh) 
    0040528F 75 00            jne         Start+7 (405291h) 
    00405291 73 00            jae         DllName+1 (405293h) 
    00405293 65 00 72 00      add         byte ptr gs:[edx],dh 
    00405297 33 00            xor         eax,dword ptr [eax] 
    00405299 32 00            xor         al,byte ptr [eax] 
    0040529B 2E 00 64 00 6C   add         byte ptr cs:[eax+eax+6Ch],ah 
    004052A0 00 6C 00 00      add         byte ptr [eax+eax],ch 
    004052A4 00 90 90 90 90 90 add         byte ptr [eax-6F6F6F70h],dl
    here is the correlating non compiled code for what is seen above..
    Code:
    #define pad __asm __emit 0x00;
    void __declspec(naked)Native_ApcLoadRoutine(PVOID p1,PVOID p2,PVOID Reserved)
    {
    	__asm
    	{
    RtlInit_U:
    		nop
    		nop
    		nop
    		nop
    		pad
    LdrLoad:
    		nop
    		nop
    		nop
    		nop
    		pad
    Start:
    		jmp InitUnicode
    		pad
    		pad
    		pad
    DllName:
    		nop 
    		nop
    		nop 
    		nop
    		nop
    as can be seen at Start i used 3 pads to fight this and that interpret correctly. but if i use less padding and code like this that writes just after the pad.
    Code:
    		Reusable = (HANDLE)((ULONG)Native_ApcLoadRoutine+0xf);
    		wcscpy((wchar_t*)Reusable,L"user32.dll");
    the compiler upon disasmbly misinterprets the jmp..
    so knowing these small 'contexts do you think that the instruction just after Start will generate issues ? with the 0x01,0x00,0x00?

    0040528A E9 0F 01 00 00 jmp InitUnicode (40539Eh)

    hopefully someone gots some words on it...
    [edit]
    someone like me for instance..
    what was a 2 byte jmp b4 is now increase because I added MAX_PATH nop(s) to DllName making my jmp now a 3byte jump and not some crazy issue with the compiler..
    and yes they 2 bytes of 0's separates this from the unicode string nicely in olly as well so i am satisfied.. with that very small bit..lol
    [/edit]

    BanMe
    Last edited by BanMe; September 7th, 2009 at 17:01.
    No hate for the lost children;
    more love for the paths we walk,
    'words' shatter the truth we seek.
    from the heart and mind of Me
    me, to you.. down and across

    No more words from me, to you...
    Hate and love shatter the heart and Mind of Me.
    For the Lost Children;For the paths we walk; the real truth we seek!

Similar Threads

  1. Replies: 0
    Last Post: February 13th, 2014, 07:42
  2. how to generat "1" instead of "uncounted" license
    By joyung in forum The Newbie Forum
    Replies: 38
    Last Post: April 10th, 2012, 03:57
  3. Replies: 4
    Last Post: May 28th, 2009, 13:02
  4. Replies: 1
    Last Post: December 14th, 2007, 13:35
  5. Can't "Step" after "Pause
    By Lena in forum OllyDbg Support Forums
    Replies: 2
    Last Post: May 5th, 2004, 21:14

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •