Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Windows Kernel structs #1219

Open
wants to merge 5 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 143 additions & 8 deletions qiling/loader/pe.py
Original file line number Diff line number Diff line change
Expand Up @@ -629,16 +629,145 @@ def init_ki_user_shared_data(self):

# initialize an instance with a few key fields
kusd_obj = kust_struct.volatile_ref(self.ql.mem, kusd_addr)
kusd_obj.ImageNumberLow = 0x014c # IMAGE_FILE_MACHINE_I386
kusd_obj.ImageNumberHigh = 0x8664 # IMAGE_FILE_MACHINE_AMD64
kusd_obj.NtSystemRoot = self.ql.os.windir
kusd_obj.NtProductType = sysconf.getint('productType')
kusd_obj.NtMajorVersion = sysconf.getint('majorVersion')
kusd_obj.NtMinorVersion = sysconf.getint('minorVersion')
kusd_obj.KdDebuggerEnabled = 0
kusd_obj.NXSupportPolicy = 0 # NX_SUPPORT_POLICY_ALWAYSOFF
kusd_obj.ImageNumberLow = 0x014c # IMAGE_FILE_MACHINE_I386
kusd_obj.ImageNumberHigh = 0x8664 # IMAGE_FILE_MACHINE_AMD64
kusd_obj.NtSystemRoot = self.ql.os.windir
kusd_obj.NtProductType = sysconf.getint('productType')
kusd_obj.NtMajorVersion = sysconf.getint('majorVersion')
kusd_obj.NtMinorVersion = sysconf.getint('minorVersion')
kusd_obj.KdDebuggerEnabled = 0
kusd_obj.NXSupportPolicy = 0 # NX_SUPPORT_POLICY_ALWAYSOFF

self.ql.os.KUSER_SHARED_DATA = kusd_obj

def init_kpcr(self):
'''
Initialisation function for KPCR structure.

This structure's pointer should always be at gs:[0x18]
'''

sysconf = self.ql.os.profile['SYSTEM']
osconf = self.ql.os.profile[f'OS{self.ql.arch.bits}']

kpcr_addr = osconf.getint('KPCR')
kpcr_struct = KPCR
self.ql.mem.map(kpcr_addr, self.ql.mem.align_up(kpcr_struct.sizeof()), info='[kpcr]')

# Get address for KPRCB structure
kprcb_addr = osconf.getint('KPRCB')

# Initialize an instance with a few key fields
# @TODO: initialize StackBase & StackLimit
kpcr_obj = kpcr_struct.volatile_ref(self.ql.mem, kpcr_addr)
kpcr_obj.MajorVersion = sysconf.getint('majorVersion')
kpcr_obj.MinorVersion = sysconf.getint('minorVersion')
kpcr_obj.CurrentPrcb = kprcb_addr # Writes _KPRCB pointer to CurrentPrcb field
kpcr_obj.Self = kpcr_addr # Writes _KPCR pointer to Self field
kpcr_obj.Prcb = kprcb_addr # Writes _KPRCB pointer to Prcb field

# Writes KPCR pointer into GS:[0x18]
self.ql.mem.write_ptr(0x6000018, kpcr_addr)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please refrain from using magic numbers; there is a constant for GS that can be used.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not a magic number. That is the exact offset for the KPRCB pointer in Windows KM. I agree that the constant + offset should be used, though.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great, that's what I meant.


# @NOTE: Tests for writing structure pointers.
# Please don't remove.
self.ql.log.warn(f"KPCR CurrentPrcb: {kpcr_obj.CurrentPrcb:x}")
self.ql.log.warn(f"KPCR Self: {kpcr_obj.Self:x}")
self.ql.log.warn(f"KPCR Prcb: {kpcr_obj.Prcb:x}")

self.ql.os.KPCR = kpcr_obj

def init_kthread(self):
'''
Initialisation function for KTHREAD structure.

This structures pointer should always be at gs:[0x188]
'''

sysconf = self.ql.os.profile['SYSTEM']
osconf = self.ql.os.profile[f'OS{self.ql.arch.bits}']

kthread_addr = osconf.getint('KTHREAD')
kthread_struct = KTHREAD
self.ql.mem.map(kthread_addr, self.ql.mem.align_up(kthread_struct.sizeof()), info='[kthread]')

# Initialize an instance with key fields
kthread_obj = kthread_struct.volatile_ref(self.ql.mem, kthread_addr)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This structure is initialized with magic numbers whose origin is unclear.
Is there a place [a Qilign object] we can take the values from? Consistency is key.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure which numbers you're referring to are magic here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh if you mean the 0x188 for GS, then same as above. Should be changed to constant + offset

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually referred to the kthread_obj fields values: 11, 0x1000, 0x1500, 0x2000?

kthread_obj.ThreadLock = 11
kthread_obj.PreviousMode = 0
kthread_obj.InitialStack = 0x1000
kthread_obj.StackBase = 0x1500
kthread_obj.StackLimit = 0x2000

# Writes KTHREAD pointer into GS:[0x188]
self.ql.mem.write_ptr(0x6000188, kthread_addr)

self.ql.os.KTHREAD = kthread_obj

def init_kprocess(self):
'''
Initialisation function for KPROCESS structure.
'''

sysconf = self.ql.os.profile['SYSTEM']
osconf = self.ql.os.profile[f'OS{self.ql.arch.bits}']

kproc_addr = osconf.getint('KPROCESS')
kproc_struct = KPROCESS
self.ql.mem.map(kproc_addr, self.ql.mem.align_up(kproc_struct.sizeof()), info='[kprocess]')

# Initialize an instance with key fields
kproc_obj = kproc_struct.volatile_ref(self.ql.mem, kproc_addr)

self.ql.os.KPROCESS = kproc_obj

def init_kprcb(self):
'''
Initialisation function for KPCRB structure.

This structures pointer should always be at gs:[0x20]
'''

sysconf = self.ql.os.profile['SYSTEM']
osconf = self.ql.os.profile[f'OS{self.ql.arch.bits}']

kprcb_addr = osconf.getint('KPRCB')
kprcb_struct = KPRCB
self.ql.mem.map(kprcb_addr, self.ql.mem.align_up(kprcb_struct.sizeof()), info='[kprcb]')

# Get address for KTHREAD & KNODE structures
kthread_addr = osconf.getint('KTHREAD')
knode_addr = osconf.getint('KNODE')

# Initialize and instance with a few key fields
kprcb_obj = kprcb_struct.volatile_ref(self.ql.mem, kprcb_addr)
kprcb_obj.CurrentThread = kthread_addr # Writes _KTHREAD pointer to CurrentThread field
kprcb_obj.IdleThread = kthread_addr # Writes _KTHREAD pointer to IdleThread field
kprcb_obj.ParentNode = knode_addr # Writes _KNODE pointer to ParentNode field

# Writes KPRCB pointer into GS:[0x20]
self.ql.mem.write_ptr(0x6000020, kprcb_addr)

self.ql.os.KPRCB = kprcb_obj

def init_knode(self):
'''
Initialisation function for KNODE structure.
'''

sysconf = self.ql.os.profile['SYSTEM']
osconf = self.ql.os.profile[f'OS{self.ql.arch.bits}']

knode_addr = osconf.getint('KNODE')
knode_struct = KNODE
self.ql.mem.map(knode_addr, self.ql.mem.align_up(knode_struct.sizeof()), info='[knode]')

# Initialize struct with a few key fields
knode_obj = knode_struct.volatile_ref(self.ql.mem, knode_addr)

self.ql.os.KNODE = knode_obj



def init_security_cookie(self, pe: pefile.PE, image_base: int):
if not Process.directory_exists(pe, 'IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG'):
Expand Down Expand Up @@ -745,6 +874,12 @@ def load(self, pe: Optional[pefile.PE]):
self.init_registry_path()
self.init_eprocess()

self.init_kprcb()
self.init_kpcr()
self.init_kthread()
self.init_kprocess()
self.init_knode()

# set IRQ Level in CR8 to PASSIVE_LEVEL
self.ql.arch.regs.write(UC_X86_REG_CR8, 0)

Expand Down
2 changes: 1 addition & 1 deletion qiling/os/windows/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
# See: https://docs.microsoft.com/en-us/windows/win32/winprog/windows-data-types

LONG = PARAM_INTN
ULONG = PARAM_INTN
ULONG = PARAM_INT32
elicn marked this conversation as resolved.
Show resolved Hide resolved
CHAR = PARAM_INT8
UCHAR = PARAM_INT16
SHORT = PARAM_INT16
Expand Down
Loading