Skip to content

Commit

Permalink
Time: Add system time manipulations.
Browse files Browse the repository at this point in the history
  • Loading branch information
matan1008 committed Mar 3, 2022
1 parent 7e22895 commit f5cb3fa
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 1 deletion.
2 changes: 2 additions & 0 deletions src/rpcclient/rpcclient/darwin/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from rpcclient.darwin.structs import utsname
from rpcclient.darwin.symbol import DarwinSymbol
from rpcclient.darwin.syslog import Syslog
from rpcclient.darwin.time import Time
from rpcclient.darwin.xpc import Xpc
from rpcclient.exceptions import RpcClientException, MissingLibraryError
from rpcclient.structs.consts import RTLD_NOW
Expand Down Expand Up @@ -67,6 +68,7 @@ def __init__(self, sock, sysname: str, hostname: str, port: int = None):
self.location = Location(self)
self.xpc = Xpc(self)
self.syslog = Syslog(self)
self.time = Time(self)

@property
def modules(self) -> typing.List[str]:
Expand Down
11 changes: 10 additions & 1 deletion src/rpcclient/rpcclient/darwin/structs.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from rpcclient.structs.consts import AF_INET, AF_INET6, AF_UNIX
from rpcclient.structs.generic import uid_t, gid_t, long, mode_t, uint64_t, short, u_short, uint32_t, u_int32_t, \
in_addr, uint8_t, u_char, UNIX_PATH_MAX
in_addr, uint8_t, u_char, UNIX_PATH_MAX, time_t

MAXPATHLEN = 1024
_SYS_NAMELEN = 256
Expand Down Expand Up @@ -712,3 +712,12 @@ def _encode(self, obj, context, path):
)

x86_thread_state64_t = STRUCT_X86_THREAD_STATE64

suseconds_t = uint32_t

timeval = Struct(
'tv_sec' / time_t,
Padding(4),
'tv_usec' / suseconds_t,
Padding(4),
)
38 changes: 38 additions & 0 deletions src/rpcclient/rpcclient/darwin/time.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
from datetime import datetime

from rpcclient.darwin.structs import timeval
from rpcclient.exceptions import MissingLibraryError
from rpcclient.structs.consts import RTLD_NOW


class Time:
def __init__(self, client):
"""
:param rpcclient.darwin.client.DarwinClient client:
"""
self._client = client
self._load_core_time_framework()

def _load_core_time_framework(self):
if self._client.dlopen('/System/Library/PrivateFrameworks/CoreTime.framework/CoreTime', RTLD_NOW):
return
raise MissingLibraryError('failed to load CoreTime')

def now(self):
with self._client.safe_calloc(timeval.sizeof()) as current:
self._client.symbols.gettimeofday(current, 0)
time_of_day = timeval.parse(current.peek(timeval.sizeof()))
return datetime.fromtimestamp(time_of_day.tv_sec + (time_of_day.tv_usec / (10 ** 6)))

def set_current(self, new_time: datetime):
self._client.symbols.TMSetAutomaticTimeZoneEnabled(0)
with self._client.safe_calloc(timeval.sizeof()) as current:
current.poke(timeval.build({'tv_sec': int(new_time.timestamp()), 'tv_usec': new_time.microsecond}))
self._client.symbols.settimeofday(current, 0)

def set_auto(self):
self._client.symbols.TMSetAutomaticTimeZoneEnabled(1)

@property
def is_set_automatically(self):
return bool(self._client.symbols.TMIsAutomaticTimeZoneEnabled())
27 changes: 27 additions & 0 deletions src/rpcclient/tests/test_time.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from datetime import datetime


def test_now(client):
"""
:param rpcclient.client.Client client:
"""
assert client.time.now() > datetime.fromtimestamp(0)


def test_set_current(client):
"""
:param rpcclient.client.Client client:
"""
try:
client.time.set_current(datetime(year=2020, month=1, day=1))
assert client.time.now() < datetime(year=2020, month=1, day=1, minute=1)
finally:
client.time.set_auto()


def test_is_set_automatically(client):
"""
:param rpcclient.client.Client client:
"""
client.time.set_auto()
assert client.time.is_set_automatically

0 comments on commit f5cb3fa

Please sign in to comment.