A forum for reverse engineering, OS internals and malware analysis 

Ask your beginner questions here.
 #6315  by Alex
 Fri May 13, 2011 5:55 pm
Yes it is possible but you have to know an offset of the Cid field which is changing from build to build. Here are some offsets:
Code: Select all
BUILD 2195 - THREAD_CID_OFFSET - 0x01E0
BUILD 2600 - THREAD_CID_OFFSET - 0x01EC
BUILD 3790 SP0 - THREAD_CID_OFFSET - 0x01F4
BUILD 3790 SP1 - THREAD_CID_OFFSET - 0x01E4
BUILD 6000 - THREAD_CID_OFFSET - 0x020C
BUILD 6001 - THREAD_CID_OFFSET - 0x020C
BUILD 6002 - THREAD_CID_OFFSET - 0x020C
BUILD 7600 - THREAD_CID_OFFSET - 0x022C
I'm not sure if all of them are correct...
 #6655  by Kayaker
 Fri Jun 03, 2011 3:24 am
Hi

You could also get the offset of the CLIENT_ID structure dynamically in a separate IOCTL call, without the use of hard-coded version specific offsets. This is just a variation on the code snippet popularized by Hoglund/Russinovich to get the offset of EProcess->ImageFileName during DriverEntry.

For reference, here's the latter method
Code: Select all
/***********************************************************

				GetOffsetOfProcessName

  Find offset of EProcess->ImageFileName, irrespective of OS version
  (Hoglund/Russinovich)  

  When called from DriverEntry we are in the System context,
  so we simply search the current EPROCESS structure 
  for the process string "system"

***********************************************************/  

ULONG GetOffsetOfProcessName()
{

  ULONG			ul_offset;
  PEPROCESS		CurrentEProcess;

  ////////////////////////////////////////////////////

   CurrentEProcess = PsGetCurrentProcess();
      
	// EPROCESS considered no larger than a page size.

   for(ul_offset = 0; ul_offset < PAGE_SIZE; ul_offset++)

   {
      if( !strncmp( "System", (PCHAR) CurrentEProcess + ul_offset,
                    strlen("System")))
      {
		  return ul_offset;
      }
   }

   return 0;

}

Here's a similar method to get the Cid, except called through an IOCTL, not DriverEntry:

Code: Select all
/***********************************************************

			GetOffsetOfCid

	Obtain offset of EThread->Cid

	  http://computer.forensikblog.de/

		_ETHREAD version 5.0.2195.7045 Microsoft Windows 2000.
		  +0x1e0 Cid       : struct _CLIENT_ID
			  +0x000 UniqueProcess
			  +0x004 UniqueThread

		_ETHREAD Version 5.1.2600.0 Windows XP. 
		  +0x1ec Cid       : struct _CLIENT_ID

		_ETHREAD Version 5.2.3790.0 Microsoft Windows Server 2003
		  +0x1f4 Cid       : struct _CLIENT_ID

***********************************************************/  

ULONG GetOffsetOfCid()
{	
	
  ULONG				ul_offset;
  ULONG				CurrentProcessId;
  PETHREAD			CurrentEThread;	


  ////////////////////////////////////////////////////

	CurrentProcessId = (ULONG)PsGetCurrentProcessId();
	CurrentEThread = PsGetCurrentThread();

	// ETHREAD considered no larger than a page size.

	for(ul_offset = 0; ul_offset < PAGE_SIZE; ul_offset++)
	{
		if( *(ULONG*) ( (BYTE*)CurrentEThread + ul_offset) == CurrentProcessId )
		{
			// found _CLIENT_ID.UniqueProcess
			return ul_offset;
		}
	}

	return 0;
	
}

You can develop similar routines to get the offsets of other fields as well, where possible. Here's one for Win32StartAddress:

Code: Select all
/***********************************************************

			GetOffsetOfWin32StartAddress

	Obtain offset of EThread->Win32StartAddress by scanning
	for our own GUI image Entry Point (EP)
	This gives us an OS version independant way of obtaining
	the absolute offset in the ETHREAD structure to locate
	the starting address of a thread.
	
	ZwQueryInformationThread/ThreadQuerySetWin32StartAddress
	might work but is not exported by Win2K.

***********************************************************/  

ULONG GetOffsetOfWin32StartAddress()
{	
	
  ULONG					ul_offset;
  PEPROCESS				CurrentEProcess;
  PETHREAD				CurrentEThread;	
  
  PIMAGE_NT_HEADERS		NtHeaders;	// "PE"
  ULONG					BaseAddress;
  ULONG					lpStartAddress;

  ////////////////////////////////////////////////////

	__try {	  

	  // Get the Entry Point from our own GUI app

		CurrentEProcess = PsGetCurrentProcess();
  
		BaseAddress = (ULONG) CurrentEProcess->Peb->ImageBaseAddress;

		NtHeaders = RtlImageNtHeader((PVOID) BaseAddress);

		lpStartAddress = BaseAddress + NtHeaders->OptionalHeader.AddressOfEntryPoint;		
			

	  ////////////////////////////////////////////////////

		// Find offset of ETHREAD.Win32StartAddress

		CurrentEThread = PsGetCurrentThread();

		// ETHREAD considered no larger than a page size.

		for(ul_offset = 0; ul_offset < PAGE_SIZE; ul_offset++)
		{

			if( *(ULONG*) ( (BYTE*)CurrentEThread + ul_offset) == lpStartAddress )

			{
				// found Win32StartAddress	
				return ul_offset;
			}
		}

	//=============================================================

	} __except (EXCEPTION_EXECUTE_HANDLER)  {

		DbgPrint ("HOOK: ERROR ExceptionCode: %x\n", GetExceptionCode() );

	}	// end __try{

	return 0;
	
}


btw, nice board guys, glad to see it's established itself ;)

Regards,
Kayaker