Log in

View Full Version : "Client" Unit Tests(some fun ones..)Indirect RtlCreateUserThread hooking..


BanMe
August 29th, 2009, 01:17
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

BanMe
August 29th, 2009, 17:46
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

Kayaker
August 29th, 2009, 22:19
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

BanMe
August 30th, 2009, 19:06
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..

Kayaker
August 31st, 2009, 01:17
Quote:
[Originally Posted by BanMe;82687]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;82687]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

BanMe
September 1st, 2009, 23:30
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?

Kayaker
September 2nd, 2009, 00:44
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.

BanMe
September 2nd, 2009, 00:54
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

Kayaker
September 2nd, 2009, 01:33
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

Woodmann
September 3rd, 2009, 18:58
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

BanMe
September 3rd, 2009, 20:35
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

BanMe
September 7th, 2009, 15:26
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...

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


BanMe