Results 1 to 13 of 13

Thread: Hooking using a Linked List to specify the params..

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

    Hooking using a Linked List to specify the params..

    im still in process of refining this so questions and comments are most welcome..

    Code:
    namespace hkHook
    {
    	struct CLLHook
    	{
    		SLIST_ENTRY HookEntry;
    		bool Installed;//0 is not installed 1 if installed
    		BYTE  Opcode;//e9 jmp e8 call
    		int   Index;
    		LPVOID pHeap;
    		DWORD TProcessId;//Targets ProcessId
    		DWORD hkTAddress;//Target Function to Hook
    		DWORD hkAddress;//Hook address
    		PVOID hkAllocAddr;
    		DWORD hkSz;//our hook size generally 5 bytes byte+dword
        };
    	typedef CLLHook* PCLLHook;
    	extern "C"
    	{
    		__checkReturn bool hkInitialize(__inout CLLHook*);//Initialization
    		__checkReturn bool hkUninitialize(void);//Destructor
    		void *RtlAllocateAlignedHeap(__in size_t, __in size_t);
    		void *hkAllocateEntry(void);//Allocate the proper structure and connects it to our list..
    		__checkReturn bool hkSetTargetExeName(__in wchar_t *);//Sets Global Exe Name used for process opening by exe name...
    		__checkReturn bool hkSetHookParams(__in_opt wchar_t *,__in LPVOID,__in LPVOID,__in DWORD,__in BYTE,__inout CLLHook *HkStruct);
    		__checkReturn bool hkInstallHook(PCLLHook,HK_ROUTINE);//installs the hook specified
    		__checkReturn bool hkDeleteNode(__in int);//Delete hook link off our list
    		wchar_t *cProcessName;//current target process name..
    		HANDLE hHeap,hWaitParams,pHeap;
    		PSLIST_ENTRY pFirstEntry = {0},pListEntry = {0};
    		PSLIST_HEADER pListHead = {0};
    		int InitPhase = 0;
    
    		void *RtlAllocateAlignedHeap(size_t size, size_t alignment )   
    		{
    			void *pa, *ptr;   
    			pa=RtlAllocateHeap(hHeap,HEAP_ZERO_MEMORY,(size+alignment-1)+sizeof(void *));   
    			if(!pa)   
    			{
    				return NULL;
    			}
    			ptr=(void*)( ((ULONG_PTR)pa+sizeof(void *)+alignment-1)&~(alignment-1) );   
    			*((void **)ptr-1)=pa;     
    			return ptr;   
    		}
    		__checkReturn bool hkInitialize(__inout CLLHook* pCLL )
    		{
    			if(InitPhase > 0)
    			{
    				return false;
    			}
    			hHeap = RtlCreateHeap(HEAP_GROWABLE|HEAP_ZERO_MEMORY,0,0,0,0,0);//64 pages reserved, 1 page allocated
      			if(hHeap != INVALID_HANDLE_VALUE && hHeap != 0)
      			{	
    				pListHead = (PSLIST_HEADER)RtlAllocateAlignedHeap(sizeof(SLIST_HEADER),MEMORY_ALLOCATION_ALIGNMENT);
    				if(!pListHead)
    				{
    					return false;
    				}
    				RtlInitializeSListHead(pListHead);
    				if(pListHead)
    				{
    					*pCLL = *(CLLHook*)hkAllocateEntry();
    					if(pCLL != 0)
    					{
    						return true;
    					}
    				}
    			}
    			return pCLL;	
    		}
    		//the destructor
    		__checkReturn bool hkUninitialize(void)
    		{
    			if(InitPhase)
    			{
    				RtlInterlockedFlushSList(pListHead);
    				RtlDestroyHeap(hHeap);
    				InitPhase = 0;
    				return true;
    			}
    			return false;
    		}
    		//Allocates Memory for new cLL Structure..
    		void *hkAllocateEntry(void)
    		{	
    			if(InitPhase)
    			{
    				return false;
    			}
    			else
    			{
    				
    				pHeap = RtlAllocateAlignedHeap(sizeof(CLLHook),MEMORY_ALLOCATION_ALIGNMENT);
    				PCLLHook pCLL = (PCLLHook)pHeap;
    				pCLL->pHeap = pHeap;
    
    				if(pCLL)
    				{
    					if(!InitPhase)
    					{
    						pFirstEntry = RtlInterlockedPushEntrySList(pListHead,&(pCLL->HookEntry));
    						InitPhase++;
    					}
    					pListEntry = RtlInterlockedPushEntrySList(pListHead,&(pCLL->HookEntry));
    					return (void*)pCLL;
    				}
    				return false;
    			}
    		}
    		__checkReturn bool hkSetTargetExeName(wchar_t *TargetProcName)
    		{
    			if(TargetProcName)
    			{
    				cProcessName = TargetProcName;
    				return true;
    			}
    			return false;
    		}
    		__checkReturn bool hkSetHookParams(__in_opt wchar_t* TargetName,__in LPVOID TargetAddr,__in LPVOID HookAddr,__in DWORD HkSz,__in BYTE Opcode,__inout CLLHook *HkStruct)
    		{
    			if(Opcode && HkSz && HookAddr && TargetAddr && InitPhase)
    			{
    				if(InitPhase == 1)
    				{
    					HkStruct->Opcode = Opcode;
    					HkStruct->hkTAddress = (DWORD)TargetAddr;
    					HkStruct->hkAddress = (DWORD)HookAddr;
    					HkStruct->hkSz = HkSz;
    					HkStruct->Index = InitPhase;
    					InitPhase++;
    					if(TargetName != 0)
    					{
    						hkSetTargetExeName(TargetName);
    						HkStruct->TProcessId = GetProcessId(UsrDrOpenProcess(cProcessName));
    					}
    					return true;
    				}
    				else
    				{
    					HkStruct->Opcode = Opcode;
    					HkStruct->hkTAddress = (DWORD)TargetAddr;
    					HkStruct->hkAddress = (DWORD)HookAddr;
    					HkStruct->hkSz = HkSz;
    					HkStruct->Index = InitPhase;
    					InitPhase++;
    					if(TargetName != 0)
    					{
    						hkSetTargetExeName(TargetName);
    						HkStruct->TProcessId = GetProcessId(UsrDrOpenProcess(cProcessName));
    					}
    					return true;
    				}
    			}
    			return false;
    		}
    		bool hkInstallHook(PCLLHook HkTempPar,HK_ROUTINE HkType)
    		{
    			BYTE ByteArray[8] = {0};
    			BYTE HookArray[8] = {0};
    			if(InitPhase >= 2)
    			{
    				PVOID pHolder = 0;
    				ULONG ProtectSize = 0;
    				DWORD oProt = 0;
    				MEMORY_BASIC_INFORMATION mbi = {0};
    				struct CLLHook HkParams = *(CLLHook*)HkTempPar;
    				if(NT_SUCCESS(NtQueryVirtualMemory(NtCurrentProcess(),(PVOID)HkParams.hkTAddress,0,&mbi,sizeof(mbi),0)))
    				{
    					if(mbi.AllocationProtect & PAGE_EXECUTE_READWRITE)
    					{
    						__asm jmp sswitch;
    					}
    					else
    					{
    						pHolder = (PVOID)HkParams.hkTAddress;
    						ProtectSize = HkParams.hkSz;
    						if(NT_SUCCESS(NtProtectVirtualMemory(NtCurrentProcess(),&pHolder,&ProtectSize,PAGE_EXECUTE_READWRITE,&oProt)))
    						{
    								__asm jmp sswitch;
    						}
    						else
    						{
    							return false;
    						}
    					}
    				}
    				return false;
    		sswitch:
    				switch (HkType)
    				{
    					case HKMOV:
    						__asm
    						{
    							pushad
    							lea        eax,HkParams
    							lea        edi,ByteArray
    							mov        esi,[eax]HkParams.hkTAddress
    							mov        ecx,0x5
    							push       esi
    							rep        movsb
    							pop        esi
    							push       eax
    							mov        al,byte ptr [eax]HkParams.Opcode
    							mov        byte ptr [esi],al
    							pop        eax
    							mov        ebx,[eax]HkParams.hkAddress
    							add        esi,5
    							sub        ebx,esi
    							sub        esi,4
    							mov        dword ptr [esi],ebx
    							popad
    						}
    						return true;
    					case HKCMPXCHG:
    						__asm
    						{
    							pushad
    							lea        eax,HkParams
    							lea        edi,ByteArray//destination
    							mov        esi,[eax]HkParams.hkTAddress//Source
    							mov        ecx,0x5
    							push       edi
    							push       esi
    							rep movsb
    							pop        esi
    							pop        edi
    							lea        ecx,HookArray
    							push       eax
    							mov        al,byte ptr [eax]HkParams.Opcode
    							mov        byte ptr [esi],al
    							pop        eax
    							mov        ebx,[eax]HkParams.hkAddress
    							add        esi,5
    							sub        ebx,esi
    							sub        esi,4
    							mov        dword ptr [ecx],ebx
    							mov        ebx,dword ptr [ecx]
    							mov        eax,[edi]
    						mxchg:
    							lock cmpxchg dword ptr [esi],ebx
    							jne  mxchg 
    							popad
    						}
    						return true;
    				default:
    					break;
    				}
    			}
    			return false;
    		}
    		__checkReturn bool hkDeleteNode(int Index)
    		{
    			PCLLHook pCLL = (PCLLHook)pFirstEntry;
    			if(pCLL->Index == Index) //case 1 corpse = Head
    			{
    				RtlFreeHeap(hHeap,0,pCLL->pHeap);
    				return true;
    			}
    			else
    			{
    			
    				while(pCLL->HookEntry.Next)
    				{
    					pCLL = (PCLLHook)pFirstEntry->Next;
    					if(pCLL->Index == Index)
    					{
    						RtlFreeHeap(hHeap,0,pCLL->pHeap);
    						return true;
    					}
    				}
    				return false;
    			}
    		}
    	}
    }
    kind regards BanMe
    Last edited by BanMe; May 27th, 2009 at 16:50. Reason: updated code.. removed "ban"ter...

  2. #2
    <script>alert(0)</script> disavowed's Avatar
    Join Date
    Apr 2002
    Posts
    1,281
    doesn't look thread-safe
    you may want to consider using this set of functions: http://msdn.microsoft.com/en-us/library/ms684121(VS.85).aspx

  3. #3
    |< x != '+' BanMe's Avatar
    Join Date
    Oct 2008
    Location
    Farmington NH
    Posts
    510
    Blog Entries
    4
    please see first post..
    Last edited by BanMe; May 27th, 2009 at 16:51.

  4. #4
    use cmpxchg8b to obtain atomicity when writing/removing your hook
    (edit: while obvious, bettr add that you should use the lock prefix and use a fixed ollydbg to debug it)
    Last edited by Maximus; May 21st, 2009 at 02:39.
    I want to know God's thoughts ...the rest are details.
    (A. Einstein)
    --------
    ..."a shellcode is a command you do at the linux shell"...

  5. #5
    |< x != '+' BanMe's Avatar
    Join Date
    Oct 2008
    Location
    Farmington NH
    Posts
    510
    Blog Entries
    4
    yes the actual testing phase is up and coming..today perhaps.. but what you are suggesting would only work for hooking locally.. this although a good idea and definitly a method of hooking "locally" i was unfamiliar with(thankx for that btw) and i may implement it with regards to hotpatching to implement global hooks that can be used with disgressionary tactics to only target certain processes..is not the original goal of this piece..but I think does deserve some incorparation and some looking into..although my ultimate goal with this is to rely on a Mapped shared section to have reliably constant Hook addresses to write our hook code with, this can and should be a logical step before I implement that part..

    but what i was asking is if this looks any more thread safe then the original above ....(and i know the hkInstallhook routine has issues. currently i am working out those issues and putting together the tests..)

    Regards BanMe
    Last edited by BanMe; May 21st, 2009 at 15:05.

  6. #6
    The only way to do a (seriously) thread-safe change *outside* the local context is to stop all the thread of the process, do the hook and then restart them (which is what a debugger usually do). So, you have to rewrite the engine to be a debugger-alike, not exactly trivial (neither that hard to do, honestly).
    I want to know God's thoughts ...the rest are details.
    (A. Einstein)
    --------
    ..."a shellcode is a command you do at the linux shell"...

  7. #7
    |< x != '+' BanMe's Avatar
    Join Date
    Oct 2008
    Location
    Farmington NH
    Posts
    510
    Blog Entries
    4
    Do you suggest NtSuspendProcess() as the method of suspending all the threads in the process,
    or should I Enumerate the threads and use NtOpenThread(),NtSuspendThread(),Write my hooks and then resume the Thread.oh and btw it is trivial when the solution you mention comes down to only a few API's

    If there is another way of suspending all the threads in a target process that I didnt mention above and that is reliable I would be highly interested in that piece of work..

    Regards BanMe
    Last edited by BanMe; May 27th, 2009 at 16:59.

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

  9. #9
    <script>alert(0)</script> disavowed's Avatar
    Join Date
    Apr 2002
    Posts
    1,281
    you have to enumerate them until you confirm that all the threads in the process (other than your thread) are suspended, and you need to enumerate them at least twice to confirm this. consider the following race condition:

    1. you enumerate the threads and see 2 threads: your thread (A) and another thread (B)
    2. you call suspendthread(B)
    3. before suspendthread is executed, a context switch happens to thread B
    4. thread B launches a new thread (C)
    5. context switch back to A, causing suspendthread to be called on B

    you still have C running.

    as such, keep iterating until you're sure no other threads were created while you were suspending the rest of them.

  10. #10
    |< x != '+' BanMe's Avatar
    Join Date
    Oct 2008
    Location
    Farmington NH
    Posts
    510
    Blog Entries
    4
    this is a valid point if the hooks are being placed after BaseProcessStartThunk has executed.. but if the hooking is done in the hook of BaseProcessStartThunk,I dont think i have to worry about other threads :]

  11. #11
    <script>alert(0)</script> disavowed's Avatar
    Join Date
    Apr 2002
    Posts
    1,281
    good point

  12. #12
    Teach, Not Flame Kayaker's Avatar
    Join Date
    Oct 2000
    Posts
    4,113
    Blog Entries
    5
    Quote Originally Posted by BanMe View Post
    if the hooking is done in the hook of BaseProcessStartThunk,I dont think i have to worry about other threads :]
    That seems reasonable. If you need to be concerned about TLS callbacks however, they would have already executed by that point and would have to be hooked at an earlier point in time.

    Just thunking out loud here... is it possible for a TLS callback to create a thread which say creates the main app/dialog box? BaseProcessStartThunk might still be called as normal, but do nothing except enter a empty message loop. The main app will be already be running in a thread you never had the chance to hook if you were keying in only on BaseProcessStartThunk.

  13. #13
    |< x != '+' BanMe's Avatar
    Join Date
    Oct 2008
    Location
    Farmington NH
    Posts
    510
    Blog Entries
    4
    I could go lower or on equal grounds by hooking BaseThreadStartThunk,CsrNewThread,LdrInitializeProcess,LdrInitializeThread,
    LdrInitializeTls,NtRequestWaitReplyPort..(as you suiggested) ,LdrLoadDll..
    So on and so forth..Prolly a whole host of other user API's and kernel api's that could accomplish this this task..But the method that I'm contemplating using is to bypass WFP for ntdll entrypoint specifically for DLL_PROCESS_ATTACH and DLL_THREAD_ATTACH..This technique can then also be combined with a Hardware Data Breakpoint overwrite on the CsrApiPort in order to redirect it(similar to kayaker's idea)..Another bypass for csrss_walker by EP_X0ff could come of this,by using EliCz idea for a native subsystem service and nyneave's build on EliCz old idea for DllMainhooks and exploratory investigation of KernelMode to User Mode Callbacks :LdrInitializeThunk as reference's..No POC's yet,its just theory...this would work for TLS callbacks that do Create Thread(s) though im not sure if it will work for ones that dont at the moment..The more I look and think about this the more I think its going to have to be a multilayer solution that combines ideas from many people and some(if not all)of them built on from different origins of attack while still accomplishing what they pioneered..Please note that I highly respect all who post there idea's, thought's and in alot of case's Code and if forget to reference something properly please forgive me and send me a PM..I will promptly change/update the reference without question...I'm also thinking of making this project Open Source in order to hopefully gain the benefits of having a community developed project. Any thoughts on this?


    http://www.nynaeve.net/?p=205

    http://www.apihooks.com/EliCZ/export.htm

    http://www.rootkit.com

    Kayaker's post was in reply to creating a Process/Thread Profiler on this forum...

    [side note:]this also caught my interest...
    http://www.woodmann.com/forum/showthread.php?t=11545

    regards BanMe

    p.s. for the source for this and other things please see my blog the client source should be up with the week of 06-22 :]
    Last edited by BanMe; June 22nd, 2009 at 17:00. Reason: (I'm american and I failz at english) o0...

Similar Threads

  1. List of exe protectors
    By ronnie291983 in forum The Newbie Forum
    Replies: 4
    Last Post: June 9th, 2010, 01:20
  2. List of functions
    By malikah in forum The Newbie Forum
    Replies: 4
    Last Post: December 10th, 2009, 11:07
  3. Linked procedure Delphi Methods???
    By 5aLIVE in forum The Newbie Forum
    Replies: 4
    Last Post: December 4th, 2005, 15:44

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
  •