flat assembler
Message board for the users of flat assembler.
Index
> Windows > fs and gs segment registers in 64 bit windows Goto page 1, 2 Next |
Author |
|
revolution 29 Apr 2023, 15:11
You can't use them. They are selectors, not segment registers.
Also, FS points to the exception handling. I can't remember what GS is for, but even if it is nothing you still can't set it to any arbitrary value. |
|||
29 Apr 2023, 15:11 |
|
tthsqe 29 Apr 2023, 16:04
I can't use them means I can't set them? The main problem is setting them. I am perfectly happy saving what the system expects them to be before any calls to foreign code and then restoring them after the foreign code returns. I do not care about exceptions from foreign code.
|
|||
29 Apr 2023, 16:04 |
|
revolution 29 Apr 2023, 16:31
You can set to other values, but not to values of your choosing, only to matching slots in the GDT. The kernel only defines a few slots in the GDT, and nothing else. They are are little value to user-mode programs.
|
|||
29 Apr 2023, 16:31 |
|
tthsqe 29 Apr 2023, 16:42
So you are saying that when my threads are minding their own business and not calling into any foreign code, the kernel still expects gs and fs to point to valid-but-unspecified locations (for context switches)?
|
|||
29 Apr 2023, 16:42 |
|
revolution 29 Apr 2023, 16:47
It isn't the kernel, it is the CPU.
Each time you set GS it will read the GDT to find the slot and load the shadow space. Your code will fault if you try to set a value that the GDT doesn't have. And the GDT has very few slots. You can probably make copy of CS, or DS, but that is about all you get, everything else will fault. |
|||
29 Apr 2023, 16:47 |
|
tthsqe 29 Apr 2023, 17:36
Let's start over since I am clearly not making myself clear. As a poor user in user land, I couldn't care less about which 16 bits actually are in fs and gs. I care about the addresses to and from which instructions like
mov rax,qword[gs:0] ; read from location X+0 mov qword[gs:8],rdx ; write to location X+8 read and write. It is my understanding that this can be any 64 bit offset X provided that gs is "set" to X. I am simply asking how I can control X as a normal user and if I need to save and/or restore X before calling into kernel32.dll, for example. The following works perfectly in linux and illustrates the point. Here I "set" gs to buffer, so X = address of buffer as above. Code: ; this program should print "good" ARCH_SET_GS = 0x1001 ARCH_SET_FS = 0x1002 ARCH_GET_FS = 0x1003 ARCH_GET_GS = 0x1004 sys_write = 0x0001 sys_arch_prctl = 0x009e sys_exit_group = 0x00e7 format ELF64 executable entry Start segment readable writeable str_good db "good",10 str_bad db "bad",10 buffer rb 1000 segment readable executable Start: ; set "gs" (whatever that means) to the address of buffer lea rsi,[buffer] mov eax,sys_arch_prctl mov edi,ARCH_SET_GS syscall mov eax,"asdf" mov dword[buffer],eax ; the following should read from the same location as mov edx,dword[buffer] mov edx,dword[gs:0] cmp eax,edx je .good .bad: mov edi,1 lea rsi,[str_bad] mov edx,4 mov eax,sys_write syscall xor edi,edi mov eax,sys_exit_group syscall .good: mov edi,1 lea rsi,[str_good] mov edx,5 mov eax,sys_write syscall xor edi,edi mov eax,sys_exit_group syscall |
|||
29 Apr 2023, 17:36 |
|
revolution 29 Apr 2023, 17:46
Okay, let's recap, just in case. As a user you can't set GS to a value of your choosing. The GDT table doesn't support it. The CPU will prevent you from setting a random value.
For the Linux code, you are using the kernel to make a new entry in the GDT which allows GS to point to some random memory location. But there is no similar Windows API you can call to ask the kernel to make a new entry in the GDT. |
|||
29 Apr 2023, 17:46 |
|
tthsqe 29 Apr 2023, 17:58
Ok, thanks. Confirms my suspicions.
|
|||
29 Apr 2023, 17:58 |
|
revolution 29 Apr 2023, 18:10
I think some confusion has come about because you mentioned segment registers in the title.
So for anyone reading that might get confused.. Segment registers only exist in real mode. In protected mode the same names (CS, DS, etc. ) are reused for the selectors, which point to entries in the GDT (and LDT). The GDT/LDT are protected memory areas that the kernel maintains, to define the execution environment for the CPU. |
|||
29 Apr 2023, 18:10 |
|
Tomasz Grysztar 29 Apr 2023, 18:27
I think you are adding to the confusion here by name-dropping GDT, when in long mode the base of FS and GS is not controlled by GDT, but by dedicated MSR. And there even are specialized instructions (RDFSBASE/RDGSBASE and WRFSBASE/WRGSBASE) that allow to access these values directly. As explained by Feryno (in the linked thread) there are additional settings to consider - but as demonstrated by my example, at least under some circumstances it can be done even from usermode.
|
|||
29 Apr 2023, 18:27 |
|
revolution 29 Apr 2023, 18:34
Oh my. I am sorry if I misled.
So in that case, does Windows enable those instructions by default? The other thread makes them sound dangerous and the results are unreliable. Heisenbugs galore. Yuck. |
|||
29 Apr 2023, 18:34 |
|
tthsqe 29 Apr 2023, 19:01
So, I am going to call the address from which mov eax,[fs:0] reads as "fsbase". How far have you pushed this fs example link? Do you really need to restore fsbase before calling the messagebox, and it is generally safe to have fsbase containing random locations while your thread is doing its own thing? This is a windows 64 question, as the answer is "yes" to the second one on my ubuntu.
|
|||
29 Apr 2023, 19:01 |
|
Tomasz Grysztar 30 Apr 2023, 12:20
Yes, it was very much needed to restore FS base immediately, and even then I don't think it was generally safe, because of possibility of an interrupt (and if scheduler wanted to drop in and do something before the FS base was restored, I would expect various kinds of disasters).
The support for such tricks on Windows comes and goes. There probably isn't anything you could rely on, because nothing on this level was officially documented as supported. See this article from 2017, which has interesting details about CR4[FSGSBASE] feature being enabled on Windows because it was used by UMS, but at the same time this information is severely outdated, because: Microsoft wrote: As of Windows 11, user-mode scheduling is not supported. All calls fail with the error ERROR_NOT_SUPPORTED. |
|||
30 Apr 2023, 12:20 |
|
revolution 30 Apr 2023, 17:38
An easy to test for problems is to put a loop and wait.
Code: wrgsbase ...
.loop:
jmp .loop Another data point can be to call a system API and see how it goes. You could put wrgsbase as the first instruction of a fasm build and use it to assemble something. It won't give proof that it works 100%, but is could give proof of failure. Edit: forgot to mention to make sure to use all cores/threads to ensure the core servicing the interrupt is involved. |
|||
30 Apr 2023, 17:38 |
|
Furs 01 May 2023, 13:43
What's the worst that can happen if it does end up interrupting? Can it crash your system? Does it generate an exception you can catch in your app? Or just silently kill your process?
Before you say "test it", I'm not going to test what happens if I detonate a bomb in my home either. Call it paranoia. |
|||
01 May 2023, 13:43 |
|
revolution 01 May 2023, 13:51
Furs wrote: What's the worst that can happen ... Failing that, I'd expect the worst to be a system crash (i.e. BSOD), requiring reboot. Perhaps using a VM with a maximum of one available thread could give some insight. |
|||
01 May 2023, 13:51 |
|
tthsqe 02 May 2023, 00:42
So, I know that libraries rely on gs (gs:88 is special, but why they chose 88 is either lucky or a bit offensive), so I won't be touching gs. When I get a brand new windows 11 installation with a top-of-the-line cpu supporting wrfsbase, i'll be sure that the first thing I do is set fsbase to a random number and put the thread in an infinite nop loop.
|
|||
02 May 2023, 00:42 |
|
Feryno 02 May 2023, 03:52
FS, GS can be changed usually in kernelmode. On instructions like MOV FS,AX / MOV GS,AX the fs/gs bases are loaded from GDT (only 32 bit bases due to GDT limitations). Because these bases are expanded to 64 bits to support 64 bit OS-es, the kernel after the MOV FS,AX / MOV GS,AX executes WRMSR instructions with these values in ECX:
Code: MSR_IA32_FS_BASE = 0C0000100h MSR_IA32_GS_BASE = 0C0000101h MSR_IA32_KERNEL_GS_BASE = 0C0000102h You cannot execute WRMSR in usermode to adjust these bases, the wrmsr instruction is ring0 privileged. Later additional methods were introduced like instructions RDFSBASE WRFSBASE RDGSBASE WRGSBASE - read the link posted by Tomasz. tthsqe found an interesting method of adjusting the bases from usermode in Linux by a syscall. On ms win x64 I don't know similar easy method, but you can run a child process as a debuggee and then adjust its registers using system calls dedicated for debugger: https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa it is necessary to set dwCreationFlags to DEBUG_PROCESS or to DEBUG_PROCESS+DEBUG_ONLY_THIS_PROCESS Kernel on switches from ring3 into ring0 executes SWAPGS as a quick way of swapping ring3 and ring0 GS bases and it also executes the same just before switching back from ring0 to ring3 (usually code sequence swapgs \ iretq, swapgs \ sysretq). So do not play with ring0 gs base |
|||
02 May 2023, 03:52 |
|
Hrstka 02 May 2023, 08:50
In 32-bit version of Windows XP there is an API call to add a new entry into the GDT. But I don't know if it still works in 64-bit Windows.
|
|||
02 May 2023, 08:50 |
|
Goto page 1, 2 Next < Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.