Burrows Code Blog

July 18, 2010

Determining If Your Process is Being Debugged

Filed under: Kernel Modules, Reverse Engineering — Tags: , , , , — burrowscode @ 9:12 pm

There are numerous situations when you may want to find out if your process is being debugged. The most notable is if you are writing a protection scheme for some software. As the ability to detect debugging can be an instrumental part of your protection. Note that the methods I am going to show you are not perfect and can be circumvented using a variety of techniques.

The first thing you can do is use the trivial IsDebuggerPresent(). This function works by checking the processes program environment block (PEB) as there is a member variable called BeingDebugged which will be set to TRUE if the process is being debugged. Thus it is simple to bypass this method by simply changing this value in the PEB.

Another way that you can check for debugging is by testing bit 8 of the FLAGS register. This is the trap flag and if set to 1 this means that the program is single stepping, a very good indication of debugging. You can accomplish this with a piece of code like this.

BOOL Is_Being_Debugged(VOID)
{
	USHORT flags;
	__asm__ (
		"pushf\n"
		"pop %0\n"
		: "=r" (flags)
		:
		: "%eax"
	);
	return ((( flags >> 8 ) & 1 ) == 1 );
}

The easiest way to circumvent this is to watch for a similar piece of code in the debugger and simply change the return value (eax). You also should be able to unset the trap flag, insert a software break point after the code, and then set the flag again.

A third way to detect when a program is being debugged involves the use of a kernel mode driver. Here we hook the system call NtCreateDebugObject(), which is used when a debugger initial attaches to a program. By intercepting this call we are able to determine when a process is attempting to debug something. I’ve included sample source for that as well.

// NtCreateDebugObject Hook
// Creative Commons - Aaron Burrow

#include "ntddk.h"

#define NTCDO_INDEX 0x37

#pragma pack(1)

typedef struct _Service_Descriptor_Entry {
	unsigned int* service_table_base;
	unsigned int* service_counter_table_base;
	unsigned int number_of_services;
	unsigned char* param_table_base;
} Service_Descriptor_Entry, *PService_Descriptor_Entry;

NTSTATUS DriverUnload(PDRIVER_OBJECT driver_object);

/* Native API */

NTSTATUS (*NtCreateDebugObject)(OUT PHANDLE, IN ACCESS_MASK,
	IN POBJECT_ATTRIBUTES, IN BOOLEAN);

NTSTATUS Hooked_Nt_CDO(OUT PHANDLE DebugObject, IN ULONG AccessRequired,
	IN POBJECT_ATTRIBUTES ObjectAttributes, IN BOOLEAN KillProcessOnExit);

extern PService_Descriptor_Entry KeServiceDescriptorTable; // SSDT
PMDL mdl; // SSDT mdl

NTSTATUS DriverEntry(PDRIVER_OBJECT driver_object, PUNICODE_STRING registry_path)
{
	unsigned int* addressable_service_table_base;

	driver_object->DriverUnload = DriverUnload;

	if (!(mdl = IoAllocateMdl(KeServiceDescriptorTable->service_table_base, KeServiceDescriptorTable->number_of_services * sizeof(unsigned int*), FALSE, TRUE, NULL)))
		return STATUS_UNSUCCESSFUL;

	MmBuildMdlForNonPagedPool(mdl);

	mdl->MdlFlags |= MDL_MAPPED_TO_SYSTEM_VA;

	// Causes a bug check on failure
	addressable_service_table_base = (PService_Descriptor_Entry)MmMapLockedPages(mdl, KernelMode);

	NtCreateDebugObject = ((PVOID*)addressable_service_table_base)[NTCDO_INDEX];
	addressable_service_table_base[NTCDO_INDEX] = (unsigned int)Hooked_Nt_CDO;
	return STATUS_SUCCESS;
}

NTSTATUS DriverUnload(PDRIVER_OBJECT driver_object)
{
	((unsigned int*)mdl->MappedSystemVa)[NTCDO_INDEX] = (unsigned int)NtCreateDebugObject;
	MmUnmapLockedPages((PVOID)mdl->MappedSystemVa, mdl);
	IoFreeMdl(mdl);
	return STATUS_SUCCESS;
}

NTSTATUS Hooked_Nt_CDO(OUT PHANDLE DebugObject, IN ULONG AccessRequired,
	IN POBJECT_ATTRIBUTES ObjectAttributes, IN BOOLEAN KillProcessOnExit)
{
	DbgPrint("Attempting to Debug!\n");
	return NtCreateDebugObject(DebugObject, AccessRequired, ObjectAttributes, KillProcessOnExit);
}

The most trivial way to defeat this method is to use an SSDT hook detection scheme.

Until later.

February 22, 2010

Exporting Non-Exported Functions in Windows PEs (Part 3 of 3)

Filed under: General Programming, Reverse Engineering — Tags: , , , , , — burrowscode @ 7:05 am

Alright here is the summation of this series of articles, it shows you a primitive algorithm for finding such functions, addressing these functions, and then finally calling on these functions. The only things that I did not implement were, an algorithm to reconstruct higher level functions (I figured this was a different project entirely), an algorithm to determine exactly the number of variables that a function expects to be passed to it (the solution I came to works fine in most circumstances), and finally I didn’t write a method that would take the non-exported functions and put them into a dll that would export them (this is primarily meant to be a POC, so this is something that someone could easily come along later and add).

Now I’ll more-or-less explain to you how the code operates.  First we give the python script the path of an executable whose functions we want to gain access too.  The script then takes the PE and maps it into memory thus allowing us to manipulate said functions.  We now go through and scan for functions using our simple algorithm, all the while recording the ends and beginnings of the functions.  The next step is to attempt to math the beginnings of the procedures with the ends, thus allowing us to see the function in it’s entirety.  This is done in calculate_function_ranges, and let me say, it was an annoying function to write.  Following this we are able to go through and make an estimate as to the number of bytes that are allowed for automatic variables in the function.  You can also see that I left room open for getting data about nested procedures, as doing so wouldn’t be too terrible.  Basically you would just need to convert the physical offset associated with the procedure to it’s virtual address, then scan through all other procedures and see if at any point a call is made to this address.  I however, am not going to implement this, at least at this time.

At this point we have the ability to actually call such functions, but doing so is a bit awkward so I’ll attempt to explain here.  So, you are allowed to call a function and give it parameters, and in the current code a maximum of 6 parameters are allowed.  Now the reason for this is pretty simple, basically I couldn’t figure out a way to take a tuple for instance, and convert it a C pointer thus allowing us to more sensibly pass different amounts of arguments.  I also tried a couple other potential solutions and they failed as well, if someone can come up with a way to do this more cleanly, I’d love to hear it.  Everything else concerned with calling functions is pretty straightforward, just give the function number, arguments, number of arguments, and you’re good to go.  The python function, call_function just makes a call to an asm function, switch_call that I wrote and stuck in a dll, which then makes a call to the actual remote function.  The dll + asm, combination was what I considered the most effective way to make the call, most other solutions I considered would have required functions pointers.

This is basically how the software works, feel free to play around with it, improve it, etc.

Here is the source code to the main python file.

# Creative Commons - Aaron Burrow
import mmap
import math
import sys
import ctypes

# When dealing with function locations, we will deal with physical offsets exclusively unless otherwise
# noted at some point. (Some operations will require that we acquire and use the virtual address)
class export_functions:
	map = None
	def __init__(self, file_name=''):
		if file_name != '':
			self.map_file(file_name)
		return None
	def __del__(self):
		if self.map != None:
			self.map.close()
	def map_file(self, file_name):
		try:
			file = open(file_name, "r+b")
			self.map = mmap.mmap(file.fileno(), 0)
		except IOError:
			print "Failed to create map!"
		return None
		
	def get_pattern_physical_offsets(self, pattern):
		occurences = []
		temp = 0
		while True:
			temp = self.map.find(pattern, temp+1)
			if temp == -1:
				break
			else:
				occurences.append(temp)
		return occurences
	
	def find_all_potential_functions(self):
		# Setup Stack Frames
		func_beg = chr(0x55) + chr(0x89) + chr(0xE5)
		# LEAVE, RET endings
		func_end = chr(0xC9) + chr(0xC3)
		# POP EBP.. endings
		alt_func_end = chr(0x89) + chr(0xEC) + chr(0x5D)
		
		starts = self.get_pattern_physical_offsets(func_beg)
		ends = self.get_pattern_physical_offsets(func_end)
		alt_ends = self.get_pattern_physical_offsets(alt_func_end)
		
		# Now we displace the ends so that the range actually goes to the last byte of the procedure
		ends = [x + 1 for x in ends]
		alt_ends = [x + 3 for x in alt_ends]

		return self.calculate_function_ranges(starts, ends + alt_ends)
		
	def calculate_function_ranges(self, starts, ends):
		s = len(starts) - 1
		ret = [[-1]*2 for i in range(len(starts) if len(starts) > len(ends) else len(ends))]
		starts.sort()
		ends.sort()
		while s >= 0:
			e = 0
			while e < len(ends):
				if starts[s] < ends[e]:
					break
				e += 1
			ret[s][0] = starts[s]
			if e != len(ends):
				ret[s][1] = ends[e]
				ends[e] = 0
			s -= 1
		if len(ends) > len(starts):
			s = len(starts)
			while s < len(ends):
				ret[s][0] = -1
				while e < len(ends):
					if ends[e] != 0:
						ret[s][1] = ends[e]
						ends[e] = 0
						break;
					e += 1
				s += 1
		return ret
	
	def get_function_info(self, ranges):
		# This function will return informatio
		locals = self.get_amount_local_variables(ranges)
		nesteds = self.get_nested_procs(ranges)
		return [(ranges[i][0], ranges[i][1], locals[i], nesteds[i]) for i in range(len(ranges))]
		
	def get_amount_local_variables(self, ranges):
		ret = [0 for i in ranges]
		i = 0
		while i < len(ranges):
			if self.map[(ranges[i][0]+3):(ranges[i][0]+5)] == chr(0x83) + chr(0xEC):
				ret[i] = ord(self.map[ranges[i][0]+5])
			else:
				ret[i] = -1
			i += 1
		return ret
		
	def get_nested_procs(self, ranges):
		ret = ["Not Implemented" for i in ranges]
		# This will require virtual address translation
		return ret
	
	def display_function_info(self, info):
		print "Function Information\n(-1 Signafies that the Information is Unavailable)\n(All Numbers are Base 10)\nFunc. #) Physical Start - Physical Stop - Local Variable Bytes - Nested Functions"
		for i in range(len(info)):
			sys.stdout.write(str(i) + ") " + str(info[i][0]) + " - " + str(info[i][1]) + " - " + str(info[i][2]) + " - " + str(info[i][3]) + "\n")
	
	def call_function(self, fn, n_args = 0, *args):
		# We just allow for a standard 6 arguments
		temp = [x for x in args]
		while len(temp) < 6:
			temp.append(0)
		code = ctypes.c_char_p(self.map[self.find_all_potential_functions()[fn][0]:self.find_all_potential_functions()[fn][1]+1])
		return ctypes.windll.export_helper.switch_call(code, temp[0], temp[1], temp[2], temp[3], temp[4], temp[5], n_args)

Now here is the dll code that we need, the assembly dialect here is FASM.

; Creative Commons - Aaron Burrow
mat PE GUI 4.0 DLL
entry DllEntryPoint

include 'win32a.inc'

section '.code' code readable executable

proc DllEntryPoint hinstDLL,fdwReason,lpvReserved
	mov eax, 0x1
	ret
endp

; long switch_call(char * func, void * args, int n_args);
proc switch_call func, arg0, arg1, arg2, arg3, arg4, arg5, n_args
	mov ecx, [n_args]
	test ecx, ecx
	jz func_call
	here:
		push [arg0 + (ecx - 1) * 4]
		loop here
	func_call:
		call [func]
	ret
endp


section '.idata' import data readable writeable

  library kernel,'KERNEL32.DLL',\
	  user,'USER32.DLL'

section '.edata' export data readable

  export 'Ret.DLL',\
	 switch_call,'switch_call'

section '.reloc' fixups data discardable

Now I’ll show you a simple example.

We will take the following PE and use the only function in it.

; Simple Example

include 'win32ax.inc' 

section '.text' code readable executable

trial:
	push ebp
	mov ebp, esp
	mov eax, [ebp + 0x8]
	add eax, [ebp + 0xC]
	mov ecx, 0x0A
	mul ecx
	mov esp, ebp
	pop ebp
	ret

Now we will want to make these calls within our python script.

x = export_functions(“C:\Users\Burrows\Code\FunctionExport\exportme.exe”)
x.display_function_info(x.get_function_info(x.find_all_potential_functions()))
print x.call_function(0, 2, 5, 4)
del(x)

Which will result in this output.

Function Information
(-1 Signafies that the Information is Unavailable)
(All Numbers are Base 10)
Func. #) Physical Start – Physical Stop – Local Variable Bytes – Nested Functions
0) 512 – 531 – -1 – Not Implemented
90

Which in fact did exactly what we wanted it to do.

I haven’t done a ton of testing with this software, although it has performed correctly in all the scenarios I’ve presented. If you find a bug, definitely let me know about it, and if you find anything cool to do with the software, then let’s hear it.

Until later.

February 20, 2010

Exporting Non-Exported Functions in Windows PEs (Part 2 of 3)

Filed under: General Programming, Reverse Engineering — Tags: , , , , , — burrowscode @ 1:07 am

Here is a primitive algorithm I put together that will scan a PE for procedures and then report it’s findings to you.  Right now it only looks for stack frames being set up, taken down, and for the LEAVE, RET instruction combination.  There is obviously a lot more that could be done with it. But it was only meant to serve as an example of how you could scan the PE.

In the next week or so you can expect a more intuitive algorithm that will scan PE’s and more effectively find functions, estimate the number of variables passed to said function, as well as attempting to reconstruct higher level functions.  Didn’t really have any time for that today as last night school called for an all nighter and that wrecked my schedule.

Until then, here is this python code which will commence the basic scan.

# Creative Commons - Aaron Burrow
import mmap

class export_functions:
	map = None
	def __init__(self, file_name=''):
		if file_name != '':
			self.map_file(file_name)
		return None
	def __del__(self):
		if self.map != None:
			self.map.close()
	def map_file(self, file_name):
		try:
			file = open(file_name, "r+b")
			self.map = mmap.mmap(file.fileno(), 0)
		except IOError:
			print "Failed to create map!"
		return None
	def get_pattern_physical_offsets(self, pattern):
		occurences = []
		temp = 0
		while True:
			temp = self.map.find(pattern, temp+1)
			if temp == -1:
				break
			else:
				occurences.append(temp)
		return occurences
	def find_all_potential_functions(self):
		# Setup Stack Frames
		func_beg = chr(0x55) + chr(0x89) + chr(0xE5)
		# LEAVE, RET endings
		func_end = chr(0xC9) + chr(0xC3)
		# POP EBP.. endings
		alt_func_end = chr(0x89) + chr(0xEC) + chr(0x5D)

		starts = self.get_pattern_physical_offsets(func_beg)
		ends = self.get_pattern_physical_offsets(func_end)
		alt_ends = self.get_pattern_physical_offsets(alt_func_end)
		print "We suspect that functions begin here: ", starts
		print "We suspect that functions end here: ", ends, alt_ends

This is how we could potentially use the code.

x = export_functions("C:\Users\Burrows\Code\something.exe")
x.find_all_potential_functions()
del(x)

Which then results in this output.

We suspect that functions begin here: [1024, 1040, 1056, 1296, 1328, 1360, 1728, 1744, 1780, 1812, 1936, 2160, 2240, 2464, 2896, 2944, 3040, 3072, 3264, 4944, 5472, 6080, 23204, 23684, 23988]
We suspect that functions end here: [1778, 1810, 1927, 2936, 3056, 3189] [2274, 2497, 23324, 23367, 23667, 23753]

Also keep in mind that these are simply the function offsets into the executable, we still need to actually map them to their callable location.

Until later.

February 18, 2010

Exporting Non-Exported Functions in Windows PEs (Part 1 of 3)

Filed under: Reverse Engineering — Tags: , , , , — burrowscode @ 10:23 am

After finishing some work today I randomly decided to hack at some PEs in OllyDbg, and while doing so I began thinking how one would go about attempting to export functions in a PE.  I didn’t really consider much how such a tool would be useful, but nonetheless I thought it would be interesting to see some of the functions that programmers are putting into software.

The task itself is quite non-trivial as the functions are not meant to be exported, so it became obvious that I would need to write some type of heuristics that would be capable of the following:

  1. Determining where a potential function begins and ends.
  2. Checking whether a function is exported or is a member of a system API.
  3. Determining where high level abstraction results in some high level function being broken into what would appear to be multiple functions at the machine code level.
  4. And finally, attempting to determine the effects and purpose of the function.

As you can see, this algorithm is going to be non-trivial and is going to take a reasonable amount of time and effort.  Although there are some things that we know right away which can be put to good use.

  1. We know how to look up the exports in the Windows PE, this is useful for determining whether a function is exported.
  2. We know how to determine whether a call is near or far (simply a matter of parsing opcodes).
  3. We also know that functions in general are abstractions of assembly routines which often take this form.
  4. ; x86 Assembly
    label:
    	push ebp
    	mov ebp, esp
    	; ...
    	; ...
    	mov esp, ebp
    	pop ebp
    

Now the issue comes down to me figuring out how to piece this information together, figuring out how to reconstruct high level functions, and generally doing a lot of coding.

Hopefully I will have some viable results in the next couples weeks or so.

Theme: WordPress Classic. Blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.