News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

Context switch: where are the registers stored?

Started by jj2007, July 31, 2016, 11:31:37 PM

Previous topic - Next topic

jj2007

I had that brilliant idea that for a debug macro, one might simply wait for context switch, then pick all register values from where Windows stored them for the context switch (XSAVE looks easier but stores only xmm etc stuff, not eax ebx ecx).

Has anybody investigated along these lines? Apparently it's a big Windows secret. It's not in TEB anyway. One surprising find is that after a Sleep, 0, some of the register values are at [esp-70h ::)]

Zen

#1
Dang,...JOCHEN,...
That IS a brilliant idea,...:bgrin:

Quote from: JOCHEN,...WHO IS RIGHT,...AGAIN,......Apparently it's a big Windows secret,...

I remember reading something about this years ago (and, unfortunately, I have forgotten all the juicy stuff by now) when I was trying to understand the concept behind the 'Call Gate descriptors' that activate kernel mode threads (when signaled from user mode), to complete the Operating System data storage and processing for the vast majority of Windows APIs (that have any kind of managerial function),...
Here is a GOOGLE search: global descriptor table register (GDTR)
...And, of course,...the definitive Wikipedia page: Global Descriptor Table, Wikipedia

Quote from: Intel 64 and IA-32 Architectures, Software Developer's Manual, Volume 3A: System Programming Guide, Part 12.7.1 Loading and Storing System Registers
The GDTR, LDTR, IDTR, and TR registers each have a load and store instruction for loading data into and storing data from the register:
• LGDT (Load GDTR Register) — Loads the GDT base address and limit from memory into the GDTR register.
• SGDT (Store GDTR Register) — Stores the GDT base address and limit from the GDTR register into memory.
• LIDT (Load IDTR Register) — Loads the IDT base address and limit from memory into the IDTR register.
• SIDT (Load IDTR Register — Stores the IDT base address and limit from the IDTR register into memory.
• LLDT (Load LDT Register) — Loads the LDT segment selector and segment descriptor from memory into the LDTR. (The segment selector operand can also be located in a general-purpose register.)
• SLDT (Store LDT Register) — Stores the LDT segment selector from the LDTR register into memory or a general-purpose register.
• LTR (Load Task Register) — Loads segment selector and segment descriptor for a TSS from memory into the task register. (The segment selector operand can also be located in a general-purpose register.)
• STR (Store Task Register) — Stores the segment selector for the current task TSS from the task register into memory or a general-purpose register.
The LMSW (load machine status word) and SMSW (store machine status word) instructions operate on bits 0 through 15 of control register CR0. These instructions are provided for compatibility with the 16-bit Intel 286 processor. Programs written to run on 32-bit IA-32 processors should not use these instructions. Instead, they should access the control register CR0 using the MOV instruction.
The CLTS (clear TS flag in CR0) instruction is provided for use in handling a device-not-available exception (#NM) that occurs when the processor attempts to execute a floating-point instruction when the TS flag is set. This instruction allows the TS flag to be cleared after the x87 FPU context has been saved, preventing further #NM exceptions. See Section 2.5, "Control Registers," for more information on the TS flag.
The control registers (CR0, CR1, CR2, CR3, CR4, and CR8) are loaded using the MOV instruction. The instruction loads a control register from a general-purpose register or stores the content of a control register in a general purpose register.

...The really unfortunate aspect of this entire line of reasoning is that: you can only call these instructions from KERNEL MODE,...(Ha,...ha,...)

...However,...if you must pursue this subject further, here are a couple of links:
Global Descriptor Table (GDT) Tutorial, OSDev,...and,...Global Descriptor Table, OSDev,...
...And,...if you just want to get lost in the OS DEV site (WARNING: You may never come back): Expanded Main Page, Welcome to OSDev.org

:bgrin: ...Of course,...there is a 'high probability' that I could be wrong about all of this stuff,...:bgrin:
...I'll bet QWORD knows all about this topic,...maybe, if I just make another inane 'MASM Compiler' post, he'll post just to let us know how completely misguided we are,...:bgrin:
Zen

mineiro

Undocumented Windows NT

Author:Prasad Dabak
Milind Borate
Sandeep Phadke
Published:October 1999
Copyright:1999
Publisher:M&T Books

SWITCHING CONTEXT

As we saw earlier, Windows NT can switch the memory context to another process by setting the appropriate page table directory. The 80386
processor requires that the pointer to the current page table directory be maintained in the CR3 register. Therefore, when the Windows NT
scheduler wants to perform a context switch to another process, it simply sets the CR3 register to the page table directory of the concerned process.

Windows NT needs to change only the memory context for some API calls such as VirtualAllocEx(). The VirtualAllocEx() API call allocates memory
in the memory space of a process other than the calling process. Other system calls that require memory context switch are ReadProcessMemory()
and WriteProcessMemory(). The ReadProcessMemory() and WriteProcessMemory() system calls read and write, respectively, memory blocks
from and to a process other than the calling process. These functions are used by debuggers to access the memory of the process being debugged.
The subsystem server processes also use these functions to access the client process's memory. The undocumented KeAttchProcess() function
from the NTOSKRNL module switches the memory context to specified process. The undocumented KeDetachProcess() function switches it back.
In addition to switching memory context, it also serves as a notion of current process. For example, if you attach to a particular process and create
a mutex, it will be created in the context of that process. The prototypes for KeAttachProcess() and KeDetachProcess() are as follows:
NTSTATUS KeAttachProcess(PEB *);
                                                                           
NTSTATUS KeDetachProcess ();

Another place where a call to the KeAttachProcess() function appears is the NtCreateProcess() system call. This system call is executed in the
context of the parent process. As a part of this system call, Windows NT needs to map the system DLL (NTDLL.DLL) in the child process's address
space. Windows NT achieves this by calling KeAttachProcess() to switch the memory context to the child process. After mapping the DLL,
Windows NT switches back to the parent process's memory context by calling the KeDetachProcess() function.

The following sample demonstrates how you can use the KeAttachProcess() and KeDetachProcess() functions. The sample prints the page
directories for all the processes running in the system. The complete source code is not included. Only the relevant portion of the code is given.
Because these functions can be called only from a device driver, we have written a device driver and provided an IOCTL that demonstrates the use
of this function. We are giving the function that is called in response to DeviceIoControl from the application. Also, the output of the program is
shown in kernel mode debugger's window (such as SoftICE). Getting the information back to the application is left as an exercise for the reader.


Other good book that I have read about windows programming was:
Undocumented Windows 2000 secrets: a programmer's cookbook / By Sven Boris Schreiber

Just an idea sir jj2007, why not use SEH to catch registers? Maybe looking inside fs segment.
I'd rather be this ambulant metamorphosis than to have that old opinion about everything

jj2007

Hi Mineiro,
Thanks, good link. There is a similar article here:

QuoteIn a context switch, the operating system has to (at a minimum):

    Enter Kernel Mode
    Save all the old threads registers.
    Acquire the dispatch spinlock.
    Determine the next thread to run (if the next thread is in another process, this can get expensive)
    Leave the dispatch spinlock.
    Swap the old threads kernel state with the new threads kernel state.
    Restore the new threads registers.
    Leave Kernel Mode

Still, no indication where they are stored :(

SEH is quite an overkill for such a simple task.

P.S.: don't call me "sir", it makes me feel very old :(

sinsi

https://en.wikipedia.org/wiki/Process_control_block

jj2007

Quote from: sinsi on August 02, 2016, 07:10:14 PM
https://en.wikipedia.org/wiki/Process_control_block

Yes, I've seen that one of course. It says vaguely "probably the PCB is in kernel stack", but no idea how to get it from there.

sinsi

>but no idea how to get it from there.
You're not supposed to know :biggrin:

The kernel should be a black box, feed it correct data and get an answer or an error.
No need to know what happens in the box.

See also a TSS segment, used for hardware task switching but not by Windows or Linux.


jj2007

Yeah, I know, you need a driver to do that. Oh well...

It's a shame that there is no "save all regs to mem" command. In x64, even pushad disappeared. XSAVE looked promising, but eax/rax and friends are not included :(

And XSAVE needs an area that is align 64. Guess what? Neither ML64 nor the Watcom family understand align 64 in .data? :(

MichaelW

Considering all of the security problems in recent years, I would expect the stored registers to be protected.
Well Microsoft, here's another nice mess you've gotten us into.

qWord

The context is saved by the scheduler on the thread's kernel stack and thus is unreachable from user land[1]. The only way I know is to use GetThreadContext when the thread is not running.




[1] Windows Internals 5th edition
MREAL macros - when you need floating point arithmetic while assembling!

Zen

#10
...Just as I expected,...QWORD knows all,...thanks, QWORD for the intel,...
...So,...back to the original post: How can you possibly hope to write a 'Debug Macro' for such a complex, and inaccessible event ???
Ok,...OK,...I certainly couldn't do it. But,...hey,...you're Italian,...we do expect miracles on occasion. :icon_eek:
Zen

hutch--

 :biggrin:

I am always fascinated by people who want to live dangerously.  :P

jj2007

Quote from: Zen on August 03, 2016, 03:23:25 AMHow can you possibly hope to write a 'Debug Macro' for such a complex, and inaccessible event ???
Ok,...OK,...I certainly couldn't do it. But,...hey,...you're Italian,...we do expect miracles on occasion. :icon_eek:

I'm almost there, not as powerful as deb but it works:

jxdeb "Testing the debug macro:", rax, rcx, rsi, xmm0, xmm1, ST(0), ST(1), ST(2), ST(3), MyR8, MyDw, MyQw
Testing the debug macro:
rax=1111111111111111
rcx=2222222222222222
rsi=5555555555555555
xmm0=1111111111111111
xmm1=2222222222222222
ST(0)=3.1415926535897931
ST(1)=98765.4321000000050000
ST(2)=12345.6789000000010000
ST(3)=3.1415926535897931
MyR8=12345678.123456780
MyDw=1234567890
MyQw=1234567890123456789
This code was assembled with ml64 in 64-bit format


Only remaining problem is the 32-bit version, which still misbehaves :(

Zen

#13
:dazzled: ...Fascinating,...:dazzled:
Zen