A forum for reverse engineering, OS internals and malware analysis 

Ask your beginner questions here.
 #27711  by aleckernel
 Fri Jan 22, 2016 9:07 am
I need to disable interrupt (CLI) for a brief moment and then re-enable it (STI). In Windows, are there any issues if we disable the interrupt for too long? If yes, how long can we disable the interrupt? i.e. from a programming point of view how long a block of code can be when it is being surrounded by CLI/STI?
 #27717  by Vrtule
 Fri Jan 22, 2016 8:48 pm
What are you trying to accomplish? Disabling interrupts may be used for synchronization purposes only on uniprocessor machines, since you need to disable them on every single processor (which cannot be done without propper synchronization on multiprocessor).

Even when (hardware) interrupts are disabled, internal interrupts, such as page faults, may still occur.
 #27718  by aleckernel
 Sat Jan 23, 2016 6:41 am
Scenario 1), I want to modify the CR3 of my thread and do something like this:

my thread:
1. modify processor's CR3
2. do something (i.e. impersonating another process context) using the new CR3
3. restore the processor's CR3

I am not sure what Windows will do when the thread context switches, say, during step 2 above (some advice welcomed).

a. if it saves up the current value of CR3 into KTHREAD, then, in theory, my modification will be visible to any other anti-whatever threads running in another processor since they can scan my KTHREAD, and with some luck in timing, can retrieve the saved modified CR3 value (_KTHREAD.ApcState->Process.DirectoryTableBase, IIRC). This is something undesirable even the chance is low. So I want to enclose the above 3 steps by CLI/STI to prevent context switching.

b. if Windows does not save up the current value of CR3, that means it copy into the CR3 the value from _KTHREAD.ApcState->Process.DirectoryTableBase directly, then any context switching between (1) - (3) will overwrite my modification and must be prevented

In this scenario, raising the IRQL to DISPATCH_LEVEL before the block may achieve the same effect but CLI/STI sounds cleaner
===========================
Scenario 2), I want to modify some struct in memory:

my thread:
1. modify some structures in memory
2. do something using the modified memory
3. restore the modified structures

Also, any anti-whatever threads running in another processor can scan the memory, and, with some luck having this happens during step 2), can detect my modifications. Hence I have to make sure the block finishes as quickly as possible. In particular it should not be pre-empted by some unknown badly written 3rd party device ISR that hangs around for too long during step 2). So the block should be enclosed by CLI/STI. (raising it to DISPATCH_LEVEL here won't work as device interrupt can interrupt it)
 #27719  by Vrtule
 Sat Jan 23, 2016 11:41 am
Ad scenario 1)
Raising an IRQL to DISPATCH_LEVEL (or higher) sounds to me as a more clear way how to tell the OS not to do any context switches on the current processor. CLI/STI is the way how to attempt to do this without the OS knowing anything.

Ad scenario 2)
If you want to operate with certain structures correctly, investigate how the OS (or the entity that owns the structures) access them, and access them in the same manner. I mean, if the structures are protected by some locks, you should acquire that locks before any access (and release the locks when you finish). When you just disable interrupts on the current processor, someone at different processor may be working with the structures already and gets really unhappy if you modify the structures "right under his/her hands". Taking control of all processors before doing the modification is also does not solve the problem if the structures are protected by passive-IRQL synchronization primitives.
 #27722  by aleckernel
 Sat Jan 23, 2016 4:31 pm
Vrtule wrote:Ad scenario 1)

Ad scenario 2)
If you want to operate with certain structures correctly, investigate how the OS (or the entity that owns the structures) access them, and access them in the same manner. I mean, if the structures are protected by some locks, you should acquire that locks before any access (and release the locks when you finish). When you just disable interrupts on the current processor, someone at different processor may be working with the structures already and gets really unhappy if you modify the structures "right under his/her hands". Taking control of all processors before doing the modification is also does not solve the problem if the structures are protected by passive-IRQL synchronization primitives.
It's not about how I modify the Windows data structures (and it is not a shared structure, so only my process has access to it), it is about how the anti-tools try to detect the kind of modifications I'll make. The way to do it quietly is to do it as quickly as possible so that nobody has the chance watch at you
Last edited by aleckernel on Sat Jan 23, 2016 4:48 pm, edited 1 time in total.
 #27723  by aleckernel
 Sat Jan 23, 2016 4:47 pm
Vrtule wrote:Ad scenario 1)
Raising an IRQL to DISPATCH_LEVEL (or higher) sounds to me as a more clear way how to tell the OS not to do any context switches on the current processor. CLI/STI is the way how to attempt to do this without the OS knowing anything.
For scenario (1), I'm actually referring to the example code in this thread

http://www.kernelmode.info/forum/viewto ... =14&t=3329

The [5-5]ForceProcMemRW shows that a way to forcefully break into the another process context is through cr3 manipulation which uses CLI/STI, although I don't agree with the positions that the example places the instructions. I list the sample code below
Code: Select all
void KReadProcessMemory(IN PEPROCESS Process, IN PVOID Address, IN UINT32 Length, OUT PVOID Buffer)
{
	ULONG64 pDTB=0,OldCr3=0,vAddr=0;
	//Get DTB
	pDTB=Get64bitValue((UCHAR*)Process + DIRECTORY_TABLE_BASE);
	if(pDTB==0)
	{
		DbgPrint("[x64Drv] Can not get PDT");
		return;
	}
	//Record old cr3 and set new cr3
	_disable();
	OldCr3=__readcr3();
	__writecr3(pDTB);
	_enable();
	//Read process memory
	if(MmIsAddressValid(Address))
	{
		RtlCopyMemory(Buffer,Address,Length);
		DbgPrint("[x64Drv] Date read: %ld", *(PDWORD)Buffer);
	}
	//Restore old cr3
	_disable();
	__writecr3(OldCr3);
	_enable();
}